В чем разница между предикатом и функциональным интерфейсом в Java8?

Я знаю, что это может быть очень простой вопрос о SO, но я хочу знать, в чем разница между Predicate и Function интерфейсом в Java8?

Predicate<String> predicateTest  = (s)-> s.length() > 5;       
System.out.println(predicateTest.test("Predicate"));

Function<String, Boolean> functionTest = str -> str.length()> 5;      
System.out.println(functionTest.apply("Function"));

Здесь, в моем примере, оба возвращаются к true. Единственное, что можно назвать, - это другое?

Ответы

Ответ 1

Разница между Predicate<T> и Function<T, R>

Прежде всего, Predicate<T> является строго булевозначной функцией:

         _ _ _ _ _ _ _ 
        |             |
  T --> |  predicate  | --> boolean
        |_ _ _ _ _ _ _|   

В то время как это не обязательно верно для Function<T, R>:

         _ _ _ _ _ _ _ 
        |             |
  T --> |   function  | --> R
        |_ _ _ _ _ _ _| 

Последний потребляет объект любого типа так же, как и Predicate<T> но может меняться в возвращаемом типе.

Используйте случай Predicate<T> и Function<T, R>

Вариант использования для Predicate<T> - это когда вам нужна функция, которая потребляет один аргумент типа T и возвращает логическое значение. например, в ситуации, когда вы хотите фильтровать поток элементов, найдите первый элемент из потока, который удовлетворяет условию как .filter(predicate).findFirst() или проверяет наличие элемента из поток, который удовлетворяет определенному условию как таковое anyMatch, noneMatch, allMatch и т.д.

Вариант использования для Function<T, R> - это когда вам нужна функция, которая потребляет один аргумент типа T и преобразует его в тип R например, который может возникать при вызове stream.map(func).

Объяснение фрагмента кода:

Что касается фрагмента примера в вашем сообщении Predicate<String> и Function<String, Boolean> - это то же самое в терминах того, что они представляют, то есть они представляют собой функцию, берущую String и возвращающую boolean. Тем не менее, первый избегает бокса возвращенное значение от boolean до Boolean тогда как последнее не делает.

Тем не менее, это не обязательно означает, что везде, где вы можете использовать Predicate<String> вы также можете использовать Function<String, Boolean> или наоборот.

Пример:

Хотя это компилируется:

Predicate<String> predicate = p -> p.length() == 21;
Stream<String> stream = stringList().stream().filter(predicate);

Это не означает:

Function<String, Boolean> function = p -> p.length() == 21;
Stream<String> stream = stringList().stream().filter(function);

и наоборот:

Хотя это работает:

Function<String, Boolean> function = p -> p.length() == 21;
Stream<Boolean> stream = stringList().stream().map(function);

Это не означает:

Predicate<String> predicate = p -> p.length() == 21;
Stream<Boolean> stream = stringList().stream().map(predicate);

Ответ 2

в этом случае нет разницы, это имеет значение только для вещей, к которым вы можете обратиться. Так, например, allMatch ожидает Predicate, вы не можете передать Function, даже если логически они делают то же самое.

Ответ 3

Ответ Aominè охватывает основные различия. Я хотел бы добавить, что оба интерфейса также имеют разные специализированные методы по умолчанию, то есть методы, которые вы можете вызвать для любого класса реализации:

  • Predicate<T>
    • Predicate<T> and(Predicate<? super T> other) - возвращает скомпилированный предикат, представляющий логику короткого замыкания AND этого предиката и другую.
    • Predicate<T> or(Predicate<? super T> other) - возвращает скомпилированный предикат, представляющий логическое ИЛИ с коротким замыканием этого предиката и другое.
    • negate() - Возвращает предикат, который представляет логическое отрицание этого предиката.
  • Function<T,R>
    • <V> Function<T,V> andThen(Function<? super R,? extends V> after) - возвращает <V> Function<T,V> andThen(Function<? super R,? extends V> after) функцию, которая сначала применяет эту функцию к ее вводу, а затем применяет функцию after к результату.
    • <V> Function<V,R> compose(Function<? super V,? extends T> before) - возвращает скомпилированную функцию, которая сначала применяет функцию before до ее ввода, а затем применяет эту функцию к результату.

Как вы можете видеть, у Predicate есть полезные методы для создания сложных условий, как и операторы, которые вы будете использовать в регулярном if, тогда как Function имеет методы, которые поддерживают простую цепочку.

Ответ 4

Predicate может возвращать только boolean (результат test()), а Function выполняет преобразование и может возвращать что-либо (результат apply()).

Predicate используется для проверки состояния.

Для преобразования используется Function.

Ответ 5

Нет никакой разницы.

Теоретически не должно быть никакого функционального различия между Predicate<T> и Function<T, Boolean>. Predicate - это просто функция, которая принимает объект некоторого типа и возвращает логическое значение. Function - это обобщение, которое может возвращать любой тип, а не только Boolean.

В самой Java могут быть детали реализации, которые делают их отличными, но они должны быть одинаковыми в теории.

Например, если интерфейс мог принимать только Predicate<String>, а не Function<String, Boolean.

Ответ 6

С технической точки зрения, Predicate<T> является просто функцией, принимающей T и возвращающей логический примитивный результат. Однако, с точки зрения использования, Predicate<T> является совершенно другим понятием, чем Function<T, Boolean>.

Мы используем Predicate<T> для выполнения операции фильтрации, например, в поточном конвейере берем Stream<T> размера n, фильтруем его с помощью Predicate<T> чтобы получить поток размером меньше или равным n. Между тем, Function<T, Boolean> в потоковом конвейере используется для выполнения операции отображения для преобразования Stream<T> в Stream<Boolean>.

Как вы можете видеть, Predicate<T> и Function<T, Boolean> технически одинаковы (игнорирование обертки Boolean для простоты), но если поставить конкретный контекст (например, потоковые конвейеры), это совершенно другая история поскольку каждый из них играет определенную роль.