Функциональный интерфейс - это интерфейс, который определяет только один абстрактный метод.
Основное назначение – использование в лямбда выражениях и method reference.
Чтобы точно определить интерфейс как функциональный, добавлена аннотация
Она обозначит замысел и не даст определить второй абстрактный метод в интерфейсе.
Интерфейс может включать сколько угодно default методов и при этом оставаться функциональным, потому что default методы - не абстрактные.
Predicate<T>
public interface Predicate<T> { boolean test(T t); }
Проверяет соблюдение некоторого условия. Если оно соблюдается, то возвращается значение true. В качестве параметра лямбда-выражение принимает объект типа T.
Function<T, R>
public interface Function<T, R> { R apply(T t); }
Представляет функцию перехода от объекта типа T к объекту типа R
Supplier<T>
public interface Supplier<T> { T get(); }
Не принимает никаких аргументов, но должен возвращать объект типа T
Consumer<T>
public interface Consumer<T> { void accept(T t); }
Выполняет некоторое действие над объектом типа T, при этом ничего не возвращая
UnaryOperator<T>
public interface UnaryOperator<T> { T apply(T t); }
принимает в качестве параметра объект типа T, выполняет над ними операции и возвращает результат операций в виде объекта типа T
BinaryOperator<T>
public interface BinaryOperator<T> { T apply(T t1, T t2); }
принимает в качестве параметра два объекта типа T, выполняет над ними бинарную операцию и возвращает ее результат также в виде объекта типа T
Интерфейс | Пример использования |
---|---|
Predicate<T> |
import java.util.function.Predicate; public class LambdaApp { public static void main(String[] args) { Predicate<Integer> isPositive = x -> x > 0; System.out.println(isPositive.test(5)); // true System.out.println(isPositive.test(-7)); // false } } |
Function<T,R> |
import java.util.function.Function; public class LambdaApp { public static void main(String[] args) { Function<Integer, String> convert = x-> String.valueOf(x) + " долларов"; System.out.println(convert.apply(5)); // 5 долларов } } |
Supplier<T> |
import java.util.Scanner; import java.util.function.Supplier; public class LambdaApp { public static void main(String[] args) { Supplier<User> userFactory = () -> { Scanner in = new Scanner(System.in); System.out.println("Введите имя: "); String name = in.nextLine(); return new User(name); }; User user1 = userFactory.get(); User user2 = userFactory.get(); System.out.println("Имя user1: " + user1.getName()); System.out.println("Имя user2: " + user2.getName()); } } Введите имя: Том Введите имя: Сэм Имя user1: Том Имя user2: Сэм |
Consumer<T> |
import java.util.function.Consumer; public class LambdaApp { public static void main(String[] args) { Consumer<Integer> printer = x-> System.out.printf("%d долларов \n", x); printer.accept(600); // 600 долларов } } |
UnaryOperator<T> |
import java.util.function.UnaryOperator; public class LambdaApp { public static void main(String[] args) { UnaryOperator<Integer> square = x -> x*x; System.out.println(square.apply(5)); // 25 } } |
BinaryOperator<T> |
import java.util.function.BinaryOperator; public class LambdaApp { public static void main(String[] args) { BinaryOperator<Integer> multiply = (x, y) -> x * y; System.out.println(multiply.apply(3, 5)); // 15 System.out.println(multiply.apply(10, -2)); // -20 } } |
Представляет набор инструкций, которые можно выделить в отдельную переменную и затем многократно вызвать в различных местах программы.
Образует реализацию метода, определенного в функциональном интерфейсе. При этом важно, что функциональный интерфейс должен содержать только один единственный метод без реализации.
список параметров выражения -> тело лямбда-выражения (действия)
Параметры лямбда-выражения должны соответствовать по типу параметрам метода из функционального интерфейса.
B лямбда-выражении использование обобщений не допускается. В этом случае нам надо типизировать объект интерфейса определенным типом, который потом будет применяться в лямбда-выражении:
public class LambdaApp {
public static void main(String[] args) {
Operationable<Integer> operation1 = (x, y)-> x + y;
Operationable<String> operation2 = (x, y) -> x + y;
System.out.println(operation1.calculate(20, 10)); //30
System.out.println(operation2.calculate("20", "10")); //2010
}
}
interface Operationable<T> {
T calculate(T x, T y);
}
Одним из ключевых моментов в использовании лямбд является отложенное выполнение (deferred execution).
То есть мы определяем в одном месте программы лямбда-выражение и затем можем его вызывать при необходимости неопределенное количество раз в различных частях программы.
Отложенное выполнение может потребоваться, к примеру, в следующих случаях:
Ссылки на методы (Method References) – это компактные лямбда выражения для методов, у которых уже есть имя.
Ссылки на методы бывают четырех видов:
Ссылка на статический метод - ContainingClass::staticMethodName
Function <String, Boolean> function = e -> Boolean.valueOf(e);
System.out.println(function.apply("TRUE"));
Function <String, Boolean> function = Boolean::valueOf;
System.out.println(function.apply("TRUE"));
Ссылка на нестатический метод конкретного объекта - containingObject::instanceMethodName
Consumer <String> consumer = e -> System.out.println(e);
consumer.accept("OCPJP 8");
Consumer <String> consumer = System.out::println;
consumer.accept("OCPJP 8");
Ссылка на нестатический метод любого объекта конкретного типа - ContainingType::methodName
Function <String, String> function = s -> s.toLowerCase();
System.out.println(function.apply("OCPJP 8"));
Function <String, String> function = String::toLowerCase;
System.out.println(function.apply("OCPJP 8"));
Ссылка на конструктор - ClassName::new
Function <String, Integer> function = (d) -> new Integer(d);
System.out.println(function.apply("4"));
Function <String, Integer> function = Integer::new;
System.out.println(function.apply("4"));