Ответ
Function<T, R> — это функциональный интерфейс из пакета java.util.function, представляющий функцию, которая принимает один аргумент типа T и возвращает результат типа R. Он является основой для операций преобразования данных, особенно в Stream API.
Основное использование:
// Определение функции: строка -> её длина
Function<String, Integer> stringLength = s -> s.length();
// Или с reference method
Function<String, Integer> stringLength = String::length;
System.out.println(stringLength.apply("Hello")); // Вывод: 5
Композиция функций: Интерфейс предоставляет методы andThen и compose для создания цепочек преобразований.
Function<Integer, Integer> multiplyByTwo = x -> x * 2;
Function<Integer, Integer> addThree = x -> x + 3;
// andThen: сначала apply исходной функции, затем переданной
Function<Integer, Integer> multiplyThenAdd = multiplyByTwo.andThen(addThree);
System.out.println(multiplyThenAdd.apply(5)); // Вывод: 13 (5*2 + 3)
// compose: сначала apply переданной функции, затем исходной
Function<Integer, Integer> addThenMultiply = multiplyByTwo.compose(addThree);
System.out.println(addThenMultiply.apply(5)); // Вывод: 16 ((5+3) * 2)
Использование в Stream API: Метод map принимает Function для преобразования элементов потока.
List<String> names = List.of("Alice", "Bob", "Charlie");
List<Integer> lengths = names.stream()
.map(String::length) // Function<String, Integer>
.collect(Collectors.toList()); // [5, 3, 7]
Практическое значение: Function позволяет инкапсулировать логику преобразования, делая код декларативным, переиспользуемым и удобным для тестирования.
Ответ 18+ 🔞
А, слушай, смотри, вот эта штука Function<T, R> — это ж, блядь, такая хитрая жопа из java.util.function. По сути, это просто контракт: "Дай мне одну хуйню типа T, а я тебе выдам другую хуйню типа R". Вся эта магия с потоками (Stream API) на нём и держится, как дурак на палке.
Ну, вот смотри, как это работает, на пальцах:
// Берём строку, выдаём её длину. Всё просто, как три копейки.
Function<String, Integer> stringLength = s -> s.length();
// Или так, чтоб совсем красиво:
Function<String, Integer> stringLength = String::length;
System.out.println(stringLength.apply("Привет")); // Напечатает: 6
А теперь самое вкусное — композиция! Это когда ты из двух простых функций делаешь одну сложную, как из двух бутылок самогона — гремучую смесь. Есть два метода: andThen и compose. Не перепутай, а то будет пиздец.
Function<Integer, Integer> умножитьНаДва = x -> x * 2;
Function<Integer, Integer> прибавитьТри = x -> x + 3;
// andThen: Сделай первое, а ПОТОМ второе. Как в жизни: сначала нажрись, потом иди спать.
Function<Integer, Integer> умножитьИПрибавить = умножитьНаДва.andThen(прибавитьТри);
System.out.println(умножитьИПрибавить.apply(5)); // Вывод: 13 (5*2=10, потом 10+3=13)
// compose: Сделай второе, а ПОТОМ первое. Как в армии: сначала отожмись, потом подумай, зачем.
Function<Integer, Integer> прибавитьИУмножить = умножитьНаДва.compose(прибавитьТри);
System.out.println(прибавитьИУмножить.apply(5)); // Вывод: 16 (5+3=8, потом 8*2=16)
Где это реально пригождается? Да везде, блядь! Особенно в этих самых Stream-ах. Метод map его просто обожает.
List<String> имена = List.of("Анна", "Борис", "Владимир");
List<Integer> длины = имена.stream()
.map(String::length) // Вот он, наш красавец Function<String, Integer>
.collect(Collectors.toList()); // Получится [4, 5, 8]
А смысл-то в чём, спросишь? А смысл, ёпта, в том, чтобы не размазывать логику преобразования по всему коду, как говно по стенке. Завернул её в аккуратную функцию — и она у тебя теперь как отдельная деталька. Её можно тестировать, переиспользовать, подсовывать куда угодно. Код становится чище, а жизнь — немного светлее. Ну, или хотя бы понятнее.