Это просто, как чайник – налил воды, нажал кнопку, получил кипяток.
В Java функциональные интерфейсы являются интерфейсами, которые содержат только один абстрактный метод (но могут иметь несколько статических и/или default методов). Они часто используются в лямбда-выражениях и потоках (streams). В стандартной библиотеке Java уже есть несколько таких интерфейсов:
Основные функциональные интерфейсы в Java:
java.lang.Runnable
- Абстрактный метод:
void run() - Используется для описания задачи, которая должна быть выполнена в отдельном потоке.
java.util.concurrent.Callable<T>
- Абстрактный метод:
T call() throws Exception - Похож на
Runnable, но возвращает результат и может выбрасывать исключение.
Интерфейсы из пакета java.util.function:
Пакет java.util.function содержит множество функциональных интерфейсов, которые полезны для работы с лямбда-выражениями и потоками:
Predicate<T>
- Абстрактный метод:
boolean test(T t) - Используется для проверки условия (например, фильтрации).
Function<T, R>
- Абстрактный метод:
R apply(T t) - Преобразует объект типа
Tв объект типаR.
Consumer<T>
- Абстрактный метод:
void accept(T t) - Принимает объект типа
T, но ничего не возвращает (используется для операций, не возвращающих результат, например, печать).
Supplier<T>
- Абстрактный метод:
T get() - Не принимает аргументов, но возвращает результат типа
T(используется для ленивой генерации данных).
UnaryOperator<T>
- Наследуется от
Function<T, T>. - Абстрактный метод:
T apply(T t) - Преобразует объект типа
Tв другой объект того же типа.
BinaryOperator<T>
- Наследуется от
BiFunction<T, T, T>. - Абстрактный метод:
T apply(T t1, T t2) - Принимает два аргумента одного типа и возвращает результат того же типа.
BiFunction<T, U, R>
- Абстрактный метод:
R apply(T t, U u) - Преобразует объекты типов
TиUв объект типаR.
BiConsumer<T, U>
Абстрактный метод: void accept(T t, U u)
Принимает два аргумента и не возвращает результата.
BiPredicate<T, U>
Абстрактный метод: boolean test(T t, U u)
Используется для проверки условия с двумя аргументами.
Примеры специализированных интерфейсов:
Java также предоставляет специализированные версии функциональных интерфейсов для примитивов int, long, и double, чтобы избежать автоупаковки/распаковки:
IntPredicate,LongPredicate,DoublePredicate: работают с примитивами.IntFunction<R>,LongFunction<R>,DoubleFunction<R>: преобразуют примитивы в другие типы.IntConsumer,LongConsumer,DoubleConsumer: потребляют примитивы.IntSupplier,LongSupplier,DoubleSupplier: поставляют примитивы.
Эти функциональные интерфейсы широко используются в Java для более лаконичного и функционального программирования.
А что по поводу Comparable?
Comparable тоже можно рассматривать как функциональный интерфейс в Java, поскольку он содержит один абстрактный метод, но с оговорками:
Comparable<T>
- Абстрактный метод:
int compareTo(T o)- Описание:
- Используется для сравнения текущего объекта с другим объектом того же типа. Возвращает отрицательное число, ноль или положительное число, если текущий объект меньше, равен или больше переданного объекта соответственно.
- Пример использования:
String,Integerи многие другие классы реализуют интерфейсComparableдля естественного упорядочивания.
Можно ли считать Comparable функциональным интерфейсом?
С технической точки зрения, Comparable<T> соответствует требованиям функционального интерфейса, так как имеет один абстрактный метод (compareTo). Это позволяет использовать его в лямбда-выражениях. Однако в реальности Comparable редко применяется в таком контексте, поскольку его основное назначение — определение естественного порядка объектов.
Тем не менее, его можно использовать в функциональном стиле, например, в методах, где ожидается Comparator (который является функциональным интерфейсом и более часто применяется в лямбдах):
List<String> list = Arrays.asList("apple", "banana", "cherry");
list.sort((s1, s2) -> s1.compareTo(s2));
В этом примере метод compareTo из интерфейса Comparable фактически используется в лямбда-выражении для сортировки списка.
A Comparator?
Comparator — это более гибкий функциональный интерфейс в Java, который используется для сравнения двух объектов. Он часто применяется, когда нужно определить порядок элементов в коллекциях или сортировать их по нестандартным критериям.
Comparator<T>
- Абстрактный метод:
int compare(T o1, T o2)- Описание:
- Сравнивает два объекта
o1иo2. Возвращает отрицательное число, ноль или положительное число, еслиo1меньше, равен или большеo2соответственно.
Преимущества Comparator над Comparable:
- Гибкость:
Comparatorпозволяет определять несколько критериев сортировки для одного и того же класса. В то время какComparableопределяет “естественный” порядок (одно определение на класс),Comparatorпозволяет создавать различные критерии сортировки.- Функциональный интерфейс:
Comparatorявляется функциональным интерфейсом, поэтому его можно использовать в лямбда-выражениях и передавать в методы, которые принимают интерфейсы функционального типа.
Методы по умолчанию и статические методы:
Comparator также содержит полезные статические и default методы для создания компараторов:
comparing:
Используется для создания Comparator на основе функции, извлекающей ключ.
Пример: List<String> list = Arrays.asList("apple", "banana", "cherry"); list.sort(Comparator.comparing(String::length)); // Сортировка по длине строки
reversed:
Инвертирует порядок компаратора.
Пример: list.sort(Comparator.comparing(String::length).reversed()); // Сортировка по длине строки в обратном порядке
thenComparing:
Используется для создания составного компаратора.
Пример: list.sort(Comparator.comparing(String::length) .thenComparing(Comparator.naturalOrder())); Здесь сначала строки сортируются по длине, а строки с одинаковой длиной — по алфавиту.
Статические методы naturalOrder и reverseOrder:
Comparator.naturalOrder() возвращает компаратор для сравнения объектов, которые реализуют Comparable.
Comparator.reverseOrder() возвращает компаратор, который сравнивает объекты в обратном порядке.
Пример использования:
List<Integer> numbers = Arrays.asList(5, 3, 8, 1, 9);
numbers.sort((n1, n2) -> n1 - n2); // Лямбда-выражение для сортировки по возрастанию
// Или используя `Comparator` более явно:
numbers.sort(Comparator.naturalOrder());
Comparator позволяет легко создавать разные способы сортировки объектов без необходимости изменять класс, к которому они принадлежат. Это делает его незаменимым в тех случаях, когда вам нужно гибко управлять сортировкой объектов.
Подводим итоги:
Получилось, конечно, несколько больше чем одна кнопка на чайнике. Но современные чайники тоже развиваются, они измеряют температуру внутри себя и умеют подогревать воду не до кипения, а до заданной температуры.
Возможно, что мы увидим все-таки и чайники с JVM внутри, о чем говорилось еще лет 20 назад… Спрошу-ка я у ИИ, как он будет выглядеть.

Промпт был такой:
Нарисуй чайник из будущего с развитым кнопочным интерфейсом.
