☕ Функциональные интерфейсы: Магия за кулисами Лямбд
Если вы используете лямбды (а вы наверняка их используете), значит, вы работаете с функциональными интерфейсами. Давайте разберем, что это такое, зачем нужна аннотация и какие интерфейсы вы обязаны знать наизусть.
🎯 Что это такое?
Функциональный интерфейс - это интерфейс, который содержит ровно один абстрактный метод.
Именно это ограничение позволяет компилятору превращать лямбда-выражение в экземпляр этого интерфейса.
💙 Примечание: В интерфейсе может быть сколько угодно
📝 Аннотация
Ставить её над интерфейсом не обязательно, но хорошим тоном считается ставить.
Зачем? Она работает как защита от дурака: если вы или ваш коллега случайно добавите второй абстрактный метод в интерфейс, компилятор сразу выдаст ошибку, не дожидаясь падения кода в местах использования лямбд.
🧰 Шпаргалка: "Великолепная четверка"
В пакете
1. Predicate
💙 Что делает: Проверяет условие.
💙 Метод:
💙 Где нужен: Фильтрация стримов (`filter`), проверки.
2. Consumer
💙 Что делает: "Потребляет" объект, ничего не возвращая.
💙 Метод:
💙 Где нужен: Вывод на экран, запись в БД,
3. Supplier
💙 Что делает: "Поставляет" объект (из ниоткуда), ничего не принимая.
💙 Метод:
💙 Где нужен: Ленивая инициализация, генерация значений,
4. Function
💙 Что делает: Превращает объект типа T в объект типа R.
💙 Метод:
💙 Где нужен: Преобразование данных,
💻 Пример в коде
🔥 Итог
Функциональные интерфейсы - это контракт для лямбда-выражений. Используйте стандартные из
#Java #Core #Lambda #FunctionalProgramming
📲 Мы в MAX
👉@BookJava
Если вы используете лямбды (а вы наверняка их используете), значит, вы работаете с функциональными интерфейсами. Давайте разберем, что это такое, зачем нужна аннотация и какие интерфейсы вы обязаны знать наизусть.
🎯 Что это такое?
Функциональный интерфейс - это интерфейс, который содержит ровно один абстрактный метод.
Именно это ограничение позволяет компилятору превращать лямбда-выражение в экземпляр этого интерфейса.
default или static методов. Главное - только один абстрактный.📝 Аннотация
@FunctionalInterfaceСтавить её над интерфейсом не обязательно, но хорошим тоном считается ставить.
Зачем? Она работает как защита от дурака: если вы или ваш коллега случайно добавите второй абстрактный метод в интерфейс, компилятор сразу выдаст ошибку, не дожидаясь падения кода в местах использования лямбд.
🧰 Шпаргалка: "Великолепная четверка"
В пакете
java.util.function уже есть готовые интерфейсы на 99% случаев жизни. Не пишите свои велосипеды, пока не выучите эти:1. Predicate
<T>boolean test(T t)2. Consumer
<T>void accept(T t)forEach.3. Supplier
<T>T get()orElseGet.4. Function
<T, R>R apply(T t)map в стримах.💻 Пример в коде
@FunctionalInterface
interface Converter {
int stringToInt(String s);
}
public class Main {
public static void main(String[] args) {
// 1. Создаем реализацию через лямбду
Converter converter = str -> Integer.parseInt(str);
// 2. Использование стандартного Consumer
java.util.function.Consumer<Integer> print = x -> System.out.println("Result: " + x);
int result = converter.stringToInt("123");
print.accept(result); // Вывод: Result: 123
}
}
🔥 Итог
Функциональные интерфейсы - это контракт для лямбда-выражений. Используйте стандартные из
java.util.function, чтобы ваш код был понятен другим разработчикам без лишних документаций.#Java #Core #Lambda #FunctionalProgramming
👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7👍1
🚀 Функциональные интерфейсы: Level Up
В первой части мы разобрали «Великолепную четверку» (
Для этого в Java есть Bi-версии и Операторы.
👯 Семейство «Bi» (Два аргумента)
Стандартные интерфейсы принимают только один параметр. Если вам нужно обработать пару значений (например, ключ и значение из Map), используйте приставку
1. BiPredicate
💙 Метод:
💙 Пример: Проверить, что длина строки
2. BiConsumer
💙 Метод:
💙 Пример:
3. BiFunction
💙 Метод:
💙 Пример: Сложить число
🔄 Семейство «Operator» (Один и тот же тип)
Часто бывает, что вы преобразуете объект, не меняя его тип (String -> String, int -> int). Писать
1. UnaryOperator
💙 Наследник
💙 Пример:
2. BinaryOperator
💙 Наследник
💙 Пример:
⚡ Осторожно с боксингом!
Дженерики (
Для примитивов есть свои спецназовцы:
💙
💙 Правило: Если работаете с числами - всегда ищите примитивный аналог интерфейса.
💻 Пример в коде
🔥 Итог
💙 Нужно 2 аргумента? Ищите Bi.
💙 Тип входа и выхода совпадает? Ищите Operator.
💙 Работаете с
#Java #AdvancedJava #FunctionalProgramming
📲 Мы в MAX
👉@BookJava
В первой части мы разобрали «Великолепную четверку» (
Predicate, Consumer, Supplier, Function). Но что делать, если нужно принять два аргумента? Или если тип входа и выхода совпадает, и лень писать лишний код?Для этого в Java есть Bi-версии и Операторы.
👯 Семейство «Bi» (Два аргумента)
Стандартные интерфейсы принимают только один параметр. Если вам нужно обработать пару значений (например, ключ и значение из Map), используйте приставку
Bi.1. BiPredicate
<T, U>boolean test(T t, U u)T больше числа U.2. BiConsumer
<T, U>void accept(T t, U u)map.forEach((k, v) -> ...) - классический пример использования.3. BiFunction
<T, U, R>R apply(T t, U u)T и число U, получить результат R.🔄 Семейство «Operator» (Один и тот же тип)
Часто бывает, что вы преобразуете объект, не меняя его тип (String -> String, int -> int). Писать
Function<String, String> - слишком длинно.1. UnaryOperator
<T>Function<T, T>.str -> str.toUpperCase() (принимает строку, возвращает строку).2. BinaryOperator
<T>BiFunction<T, T, T>.(a, b) -> a + b (два числа на вход, одно число на выход). Именно он используется в Stream.reduce.⚡ Осторожно с боксингом!
Дженерики (
<T>) работают только с объектами. Если вы используете Function<Integer, Integer> для математики, Java будет постоянно распаковывать и запаковывать int в Integer, что бьет по производительности.Для примитивов есть свои спецназовцы:
IntPredicate, LongConsumer, DoubleFunction и т.д.💻 Пример в коде
import java.util.function.*;
public class AdvancedLambdas {
public static void main(String[] args) {
// 1. BinaryOperator: объединяем две строки
BinaryOperator<String> concat = (s1, s2) -> s1 + " " + s2;
System.out.println(concat.apply("Hello", "Java"));
// 2. BiPredicate: проверяем, начинается ли строка с префикса
BiPredicate<String, String> startsWith = (str, prefix) -> str.startsWith(prefix);
System.out.println(startsWith.test("Telegram", "Tele")); // true
// 3. IntUnaryOperator: работаем с примитивами без лишних объектов
IntUnaryOperator square = x -> x * x;
System.out.println(square.applyAsInt(5)); // 25
}
}
🔥 Итог
int/long/double? Ищите интерфейсы с префиксом типа.#Java #AdvancedJava #FunctionalProgramming
👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6