Функциональные интерфейсы
Интерфейс задаёт форму поведения
Lambda-выражению нужен тип. В Java таким типом служит функциональный интерфейс — интерфейс ровно с одним абстрактным методом. Параметры этого метода определяют параметры lambda, а возвращаемый тип — то, что lambda должна вернуть.
@FunctionalInterface
interface TextRule {
boolean test(String value);
}
TextRule longText = text -> text.length() >= 5;
System.out.println(longText.test("Java"));
У интерфейса могут быть default- и static-методы:
они не добавляют новых абстрактных требований и не мешают интерфейсу оставаться функциональным.
Аннотация @FunctionalInterface не обязательна,
но помогает компилятору проверить это намерение.
Главные интерфейсы из java.util.function
Для типовых сценариев свои интерфейсы создавать не нужно.
Пакет java.util.function содержит готовые варианты:
Predicate<T>— получает значение и возвращаетboolean;Function<T, R>— преобразует значение типаTвR;Consumer<T>— получает значение и ничего не возвращает;Supplier<T>— ничего не получает и создаёт или предоставляет значение;UnaryOperator<T>иBinaryOperator<T>— частные случаи функций, где вход и результат имеют один тип.
Predicate<String> isLong = text -> text.length() >= 5;
Function<String, Integer> length = String::length;
Consumer<String> print = System.out::println;
Supplier<String> message = () -> "Ready";
Названия хорошо подсказывают смысл. Predicate отвечает на вопрос,
Function преобразует, Consumer потребляет,
а Supplier предоставляет значение.
Эти интерфейсы постоянно встречаются в Stream API и других частях стандартной библиотеки.
Один интерфейс — разные реализации
Переменная функционального интерфейса может хранить lambda, ссылку на метод или обычный объект класса, который реализует этот интерфейс. Для вызывающего кода разницы нет: он работает с методом интерфейса.
Predicate<String> startsWithJ = text -> text.startsWith("J");
if (startsWithJ.test("Java")) {
System.out.println("match");
}
Predicate,
Function, Consumer или Supplier,
обычно лучше использовать готовый тип.