Функциональные интерфейсы

Вопросы к собеседованию

Вопросы:

Функциональные интерфейсы

Функциональный интерфейс - это интерфейс, который определяет только один абстрактный метод.

Основное назначение – использование в лямбда выражениях и method reference.

Чтобы точно определить интерфейс как функциональный, добавлена аннотация @FunctionalInterface , работающая по принципу @Override.

Она обозначит замысел и не даст определить второй абстрактный метод в интерфейсе.

Интерфейс может включать сколько угодно default методов и при этом оставаться функциональным, потому что default методы - не абстрактные.


Встроенные функциональные интерфейсы:

Интерфейс Пример использования
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) – это компактные лямбда выражения для методов, у которых уже есть имя.

Ссылки на методы бывают четырех видов: