Шаг 113.
Язык программирования Java.
Функциональные интерфейсы

На этом шаге мы рассмотрим функциональные интерфейсы

Ранее мы говорили об лямбда-выражениях. Но как мы знаем, у каждого результата выражения есть тип. Следовательно, у лямбд тоже должен быть тип. Все дело в том, что в Java любому лямбда-выражению соответствует интерфейс. Такие интерфейсы всегда содержат только один абстрактный метод. Но они могут содержать сколько угодно методов с реализацией по умолчанию (помеченные ключевым словом default). Также они помечены специальной аннотацией @FunctionalInterface. Такие интерфейсы носят название функциональные интерфейсы. В Java все стандартные функциональные интерфейсы лежат в пакете java.util.function. В приведенной ниже таблице приведены наиболее часто используемые интерфейсы.

Таблица 1. Стандартные функциональные интерфейсы
Интерфейс Описание
Consumer<T> Данный интерфейс нужен для выполнения каких-то действий над объектом, при этом не нуждаясь в возвращении каких-то значений. Содержит функцию accept, которая принимает объект типа T и выполняет над ним требуемые действия.
Function<T,R> Данный интерфейс нужен для перехода от объекта типа T к объекту типа R. Содержит функцию apply, которая принимает объект типа T и возвращает объект типа R.
Predicate<T> Проверяет соблюдение некоторого условия. В интерфейсе содержится функция test, которая принимает аргумент типа T, и возвращает значение true, если аргумент удовлетворяет предикату, и false в противном случае.
Supplier<T> Данный интерфейс содержит функцию get, которая ничего не принимает, но при этом возвращает значение типа T. Такой интерфейс применяется, например, когда нужно лямбда-выражение без аргументов.
UnaryOperator<T> Данный интерфейс представляет собой какую-то унарную операцию. Наследуется от интерфейса Function.
BinaryOperator<T> Данный интерфейс представляет собой какую-то бинарную операцию. Содержит функцию apply (наследуется от интерфейса BiFunction), которая принимает два аргумента типа T, выполняет над ними бинарную операцию и возвращает ее результат также в виде объекта типа T.
BiConsumer<T,U> То же что и Consumer, только принимает два значения вместо одного.
BiFunction<T,U,R> То же что и Function, только принимает два значения вместо одного.
BiPredicate<T,U> То же что и Predicate, только принимает два значения вместо одного.


Приведем ниже пример использования функциональных интерфейсов.


import java.util.Random;
import java.util.function.*;

public class Main {
    public static void main(String[] args) {
        // Лямбда-выражение для увеличения числа в два раза
      Consumer<Integer> consumerTest = v -> System.out.println(v + " * 2 = " + v * 2);
        consumerTest.accept(12);

        // Лямбда-выражение для возведение числа в квадрат
        Function<Integer, String> functionTest = v -> String.valueOf(v * v);
        System.out.println("12 ^ 2 = " + functionTest.apply(12));

        // Лямбда-выражение для проверки числа на четность
        Predicate<Integer> predicateTest = v -> v % 2 == 0;
        System.out.println("12 это четное число: " + ((predicateTest.test(12)) ? "Да" 
                                                                            : "Нет"));
        System.out.println("13 это четное число: " + ((predicateTest.test(13)) ? "Да" 
                                                                            : "Нет"));

        // Лямбда-выражение для получения произвольного числа
        Supplier<Integer> supplierTest = () -> {
            Random random = new Random();
            return random.nextInt(100);
        };
        System.out.println("Получение произвольного числа: " + supplierTest.get());

        // Лямбда-выражение для пользовательской унарной операции
        UnaryOperator<Integer> unaryOperatorTest = v -> v * 2 - 1;
        System.out.println("12 * 2 - 1 = " + unaryOperatorTest.apply(12));

     // Лямбда-выражение для пользовательской бинарной операции (возведения в степень)
        BinaryOperator<Integer> binaryOperator = (a, b) -> {
            int c = 1;
            for (int i = 0; i < b; i++) {
                c *= a;
            }
            return c;
        };
        System.out.println("2 ^ 4 = " + binaryOperator.apply(2, 4));
    }
}

Проект можно взять здесь


Рис. 1. Вывод программы


На следующем шаге мы приведем примеры использования лямбда-выражений

Предыдущий шаг Содержание Следующий шаг