Функциональные интерфейсы
Функциональный интерфейс — это интерфейс, у которого ровно один абстрактный метод.
Именно такие интерфейсы можно реализовать через лямбда-выражение или ссылку на метод.
В пакете java.util.function собраны готовые универсальные функциональные
интерфейсы для типовых задач: преобразовать значение, проверить условие, что-то
сделать с объектом, поставить значение.
Аннотация @FunctionalInterface не обязательна, но желательна: компилятор
проверит, что у интерфейса действительно один абстрактный метод, и не даст
случайно добавить второй.
Базовые интерфейсы
Function<T, R> R apply(T t) // преобразование T -> R
Predicate<T> boolean test(T t) // проверка
Consumer<T> void accept(T t) // действие без возврата
Supplier<T> T get() // поставщик значений
BiFunction<T, U, R> R apply(T, U) // два аргумента -> результат
UnaryOperator<T> T apply(T t) // T -> T
BinaryOperator<T> T apply(T, T) // (T, T) -> T
Примеры
Пример 1. Function
import java.util.function.Function;
public class FunctionDemo {
public static void main(String[] args) {
Function<Integer, String> labelDistance = cm -> "Расстояние = " + cm + " см";
System.out.println(labelDistance.apply(15));
System.out.println(labelDistance.apply(120));
}
}
Output:
Расстояние = 15 см
Расстояние = 120 см
Пример 2. Predicate
import java.util.function.Predicate;
public class PredicateDemo {
public static void main(String[] args) {
Predicate<Integer> tooClose = d -> d < 10;
Predicate<Integer> tooFar = d -> d > 100;
Predicate<Integer> bad = tooClose.or(tooFar);
System.out.println(bad.test(5));
System.out.println(bad.test(50));
System.out.println(bad.test(200));
}
}
Output:
true
false
true
Пример 3. Consumer
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
public class ConsumerDemo {
public static void main(String[] args) {
Consumer<String> log = msg -> System.out.println("[LOG] " + msg);
List<String> events = Arrays.asList("старт", "движение", "стоп");
events.forEach(log);
}
}
Output:
[LOG] старт
[LOG] движение
[LOG] стоп
Пример 4. Supplier
import java.util.function.Supplier;
public class SupplierDemo {
public static void main(String[] args) {
Supplier<Long> now = () -> System.currentTimeMillis() / 1000;
System.out.println("UNIX-время (с): " + now.get());
System.out.println("Повтор: " + now.get());
}
}
Output:
UNIX-время (с): 1747300000
Повтор: 1747300000
(точные значения зависят от текущего времени).
Пример 5. Собственный @FunctionalInterface
public class CustomFunctional {
@FunctionalInterface
interface SensorReader {
int read(String pin);
}
static int average(SensorReader reader, String pin, int samples) {
int sum = 0;
for (int i = 0; i < samples; i++) sum += reader.read(pin);
return sum / samples;
}
public static void main(String[] args) {
SensorReader fake = pin -> pin.length() * 100;
System.out.println(average(fake, "A0", 4));
System.out.println(average(fake, "ECHO", 4));
}
}
Output:
200
400
Пример 6. Композиция Function
import java.util.function.Function;
public class FunctionCompose {
public static void main(String[] args) {
Function<Integer, Integer> plus10 = x -> x + 10;
Function<Integer, Integer> times2 = x -> x * 2;
Function<Integer, Integer> combo = plus10.andThen(times2);
System.out.println(combo.apply(5)); // (5+10)*2
Function<Integer, Integer> combo2 = plus10.compose(times2);
System.out.println(combo2.apply(5)); // (5*2)+10
}
}
Output:
30
20
Подводные камни
Предупреждение
@FunctionalInterfaceзапрещает второй абстрактный метод, но допускаетdefault- иstatic-методы.Примитивные типы при использовании
Function<Integer, Integer>боксятся в объекты. Для производительности естьIntFunction,IntPredicate,IntUnaryOperatorи т.п.Predicate.and/or/negateвозвращают новый Predicate — исходный не меняется.Не путайте
andThenиcompose:a.andThen(b)сначалаa, потомb;a.compose(b)сначалаb, потомa.
См. также
Примечание
Материал подготовлен по мотивам Oracle Java Tutorials и документации пакета
java.util.function, распространяется в рамках
Oracle Free Documentation License. Текст написан своими словами,
примеры кода — оригинальные.