Vị ngữ trong Java


100

Tôi đang xem qua mã sử dụng Predicatetrong Java. Tôi chưa bao giờ sử dụng Predicate. Ai đó có thể hướng dẫn tôi bất kỳ hướng dẫn hoặc giải thích khái niệm nào Predicatevà việc triển khai nó trong Java không?


4
Bạn đang nói về Guava's Predicate? Một cái gì đó tương tự? Một cái gì đó hoàn toàn khác?
polygenelubricants

2
Ngoài ra còn có Apache CommonsPredicate
Dan Gravell

Câu trả lời:


203

Tôi cho rằng bạn đang nói đến com.google.common.base.Predicate<T>từ Guava.

Từ API:

Xác định một truehoặc falsegiá trị cho một đầu vào nhất định. Ví dụ: a RegexPredicatecó thể triển khai Predicate<String>và trả về true cho bất kỳ chuỗi nào phù hợp với biểu thức chính quy đã cho của nó.

Đây thực chất là một bản tóm tắt OOP cho một booleanbài kiểm tra.

Ví dụ: bạn có thể có một phương thức trợ giúp như thế này:

static boolean isEven(int num) {
   return (num % 2) == 0; // simple
}

Bây giờ, với một List<Integer>, bạn chỉ có thể xử lý các số chẵn như sau:

    List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
    for (int number : numbers) {
        if (isEven(number)) {
            process(number);
        }
    }

Với Predicate, ifbài kiểm tra được tóm tắt dưới dạng một kiểu. Điều này cho phép nó tương tác với phần còn lại của API, chẳng hạn như API Iterablescó nhiều phương thức tiện ích Predicate.

Vì vậy, bây giờ bạn có thể viết một cái gì đó như sau:

    Predicate<Integer> isEven = new Predicate<Integer>() {
        @Override public boolean apply(Integer number) {
            return (number % 2) == 0;
        }               
    };
    Iterable<Integer> evenNumbers = Iterables.filter(numbers, isEven);

    for (int number : evenNumbers) {
        process(number);
    }

Lưu ý rằng giờ đây vòng lặp for-each đơn giản hơn nhiều mà không cần ifkiểm tra. Chúng tôi đã đạt đến cấp độ rút ngắn cao hơn bằng cách xác định Iterable<Integer> evenNumbers, bằng filtercách sử dụng a Predicate.

Liên kết API


Trên chức năng bậc cao hơn

Predicatecho phép Iterables.filterphục vụ như những gì được gọi là một hàm bậc cao hơn. Riêng nó, điều này mang lại nhiều lợi thế. Lấy List<Integer> numbersví dụ trên. Giả sử chúng ta muốn kiểm tra xem tất cả các số đều dương. Chúng ta có thể viết một cái gì đó như thế này:

static boolean isAllPositive(Iterable<Integer> numbers) {
    for (Integer number : numbers) {
        if (number < 0) {
            return false;
        }
    }
    return true;
}

//...
if (isAllPositive(numbers)) {
    System.out.println("Yep!");
}

Với Predicatevà tương tác với phần còn lại của các thư viện, thay vào đó chúng ta có thể viết như sau:

Predicate<Integer> isPositive = new Predicate<Integer>() {
    @Override public boolean apply(Integer number) {
        return number > 0;
    }       
};

//...
if (Iterables.all(numbers, isPositive)) {
    System.out.println("Yep!");
}

Hy vọng rằng bây giờ bạn có thể thấy giá trị trong các quy trình trừu tượng cao hơn cho các quy trình như "lọc tất cả các phần tử theo vị từ đã cho", "kiểm tra xem tất cả các phần tử có thỏa mãn vị từ đã cho hay không", v.v. để tạo mã tốt hơn.

Thật không may, Java không có các phương thức hạng nhất: bạn không thể chuyển các phương thức xung quanh đến Iterables.filterIterables.all. Tất nhiên, bạn có thể truyền xung quanh các đối tượng trong Java. Do đó, Predicatekiểu được xác định và bạn chuyển các đối tượng triển khai giao diện này thay thế.

Xem thêm


4
Tôi đã không đề cập đến Vị từ của Guava, đáng lẽ tôi phải rõ ràng trong câu hỏi của mình, nhưng lời giải thích của bạn đã giúp tôi hiểu những gì tôi đang tìm kiếm, cách logic vị từ được sử dụng trong java. Cảm ơn vì lời giải thích cặn
kẽ

@polygenelubricants, Tại sao lại phát minh ra Predicate<Integer>khi chúng ta đã có F<Integer, Boolean>cái nào làm được điều tương tự?
Pacerier

Bạn cũng có thể làm điều đó theo cách của java 8: List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); Predicate<Integer> isEven = integer -> (integer % 2) == 0; Iterable<Integer> evenNumbers = numbers.stream().filter(isEven).collect(Collectors.toList());

14

Vị từ là một hàm trả về giá trị true / false (tức là boolean), trái ngược với mệnh đề là giá trị true / false (tức là boolean). Trong Java, người ta không thể có các hàm độc lập, và vì vậy người ta tạo một vị từ bằng cách tạo một giao diện cho một đối tượng đại diện cho một vị từ và sau đó người ta cung cấp một lớp thực hiện giao diện đó. Ví dụ về giao diện cho một vị từ có thể là:

public interface Predicate<ARGTYPE>
{
    public boolean evaluate(ARGTYPE arg);
}

Và sau đó bạn có thể có một triển khai như:

public class Tautology<E> implements Predicate<E>
{
     public boolean evaluate(E arg){
         return true;
     }
}

Để hiểu rõ hơn về khái niệm, bạn có thể muốn đọc về logic bậc nhất.

Chỉnh sửa
Có một giao diện Predicate chuẩn ( java.util. Chức năng.Predicate ) được định nghĩa trong Java API của Java 8. Trước Java 8, bạn có thể thấy thuận tiện khi sử dụng lại giao diện com.google.common.base.Predicate từ Ổi .

Ngoài ra, lưu ý rằng kể từ Java 8, việc viết các vị từ bằng cách sử dụng lambdas đơn giản hơn nhiều. Ví dụ, trong Java 8 trở lên, người ta có thể truyền p -> truecho một hàm thay vì xác định một lớp con Tautology được đặt tên như trên.


0

Bạn có thể xem các ví dụ về java doc hoặc ví dụ về cách sử dụng Predicate tại đây

Về cơ bản, nó được sử dụng để lọc các hàng trong tập kết quả dựa trên bất kỳ tiêu chí cụ thể nào mà bạn có thể có và trả về true cho những hàng đáp ứng tiêu chí của bạn:

 // the age column to be between 7 and 10
    AgeFilter filter = new AgeFilter(7, 10, 3);

    // set the filter.
    resultset.beforeFirst();
    resultset.setFilter(filter);

Tôi đang đề cập đến vị từ commons, không liên quan đến Tập kết quả. cảm ơn mặc dù
srikanth

0

Bổ sung vào những gì Micheal đã nói:

Bạn có thể sử dụng Predicate như sau để lọc các bộ sưu tập trong java:

public static <T> Collection<T> filter(final Collection<T> target,
   final Predicate<T> predicate) {
  final Collection<T> result = new ArrayList<T>();
  for (final T element : target) {
   if (predicate.apply(element)) {
    result.add(element);
   }
  }
  return result;
}

một vị từ khả dĩ có thể là:

final Predicate<DisplayFieldDto> filterCriteria = 
                    new Predicate<DisplayFieldDto>() {
   public boolean apply(final DisplayFieldDto displayFieldDto) {
    return displayFieldDto.isDisplay();
   }
  };

Sử dụng:

 final List<DisplayFieldDto> filteredList=
 (List<DisplayFieldDto>)filter(displayFieldsList, filterCriteria);

1
Căn bản không phải là loại đánh bại mục đích sao? Lý do chính trong việc chọn cách tiếp cận chức năng là KHÔNG lặp lại theo cách thủ công và loại bỏ for. Mức độ trừu tượng trở nên cao hơn và mạnh mẽ hơn - tuy nhiên, việc làm theo cách thủ công sẽ đánh bại mục đích đó và quay trở lại mức độ trừu tượng thấp.
Eugen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.