JavaRush /Курсы /Java Syntax Pro /Функциональный метод

Функциональный метод

Java Syntax Pro
18 уровень , 1 лекция
Открыта

1. Функциональные методы

Если у интерфейса есть только один метод, переменной этого типа-интерфейса можно присвоить значение, заданное лямбда-выражением (лямбда-функцией). Такие интерфейсы стали называть функциональными интерфейсами (после добавления в Java поддержки лямбда-функций).

Например, в Java есть интерфейс Consumer<Тип> (Consumer == Потребитель), который содержит метод accept(Тип obj). Зачем же нужен этот интерфейс?

В Java 8 у коллекций появился метод forEach(), который позволяет для каждого элемента коллекции выполнить какое-нибудь действие. И вот для передачи действия в метод forEach() как раз и используется функциональный интерфейс Consumer<T>.

Вот как можно вывести все элементы коллекции на экран:

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "Привет", "как", "дела?");

list.forEach( (s) -> System.out.println(s) );
Вывод всех элементов коллекции (с использованием лямбда-выражения)

Компилятор преобразует этот код в код:

ArrayList<String> list = new ArrayList<>();
Collections.addAll(list, "Привет", "как", "дела?");

list.forEach(new Consumer<String>()
{
   public void accept(String s)
   {
      System.out.println(s);
   }
});
Вывод всех элементов коллекции (запись с использованием анонимного класса)

Первая запись однозначно короче, чем вторая. И хотя читать код с лямбда-выражениями непросто, читать код с анонимными внутренними классами порой еще сложнее.



2. Ссылка на метод

Однако наш код с лямбда-выражением можно записать еще короче.

Во-первых, можно опустить скобки вокруг параметра s:

list.forEach( (s) -> System.out.println(s) );
Было
list.forEach( s -> System.out.println(s) );
Стало

Так можно делать только если параметр один. Если параметров несколько, нужно использовать скобки.

Ну а во-вторых, можно записать так:

list.forEach( System.out::println );
Самая компактная запись

Это все одна и та же запись. Обратите внимание, что после println нет скобок.

Тут записан один и тот же код — вызов метода:

объект::метод
x -> объект.метод(x)

Подумайте сами: мы хотели для каждого элемента коллекции list выполнять какое-то действие. Если это действие — вызов одной функции (такой как println()), было бы разумно просто передать функцию в метод в качестве параметра.

А как объяснить компилятору, что функцию нужно именно передать, а не вызвать? Для этого перед именем метода ставим не точку, а два двоеточия: одно двоеточие уже занято в тернарном операторе.

Это и есть самая простая и компактная запись.



3. Конструктор

Ссылки на методы с помощью двойного двоеточия очень удобно использовать, когда мы будем работать с потоками ввода-вывода. Вы в этом убедитесь чуть позже

А пока давайте поговорим о 3 популярных способах передачи ссылки на метод:

Ссылка на метод объекта

Чтобы передать ссылку на метод объекта, нужно записать код вида объект::метод.
Этот код эквивалентен коду x -> объект.метод(x).

В качестве объекта могут фигурировать такие специальные переменные как this и super.

Ссылка на метод класса

Чтобы передать ссылку на статический метод, нужно записать код вида класс::метод. Этот код будет преобразован к коду вида x -> класс.метод(x);

Ссылка на конструктор

Конструктор по своему поведению чем-то похож на статический метод класса, поэтому на него тоже можно передать ссылку. Выглядит это так: класс::new.

Например, можно обойти стирание типов у коллекций и передать в метод toArray() ссылку на конструктор, который создаст нужный массив: toArray( int[]::new );


Комментарии (280)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Андрей Руденко Уровень 21
13 октября 2025
Очень интересно но не понятно НИЧЕГО
Виктор Уровень 23
29 сентября 2025
Что-то получилось, а как потом разберемся
Руслан Уровень 46
23 сентября 2025
Ох ну и ж....
Anonymous #3585174 Уровень 33
23 июля 2025
like
Рифати Уровень 66
5 июля 2025
Exaltyr777 Уровень 25
9 августа 2025
Есть такое
ShadyLine Уровень 30
6 апреля 2025
Хорошая увлекательная тема, но полагаю сложно будет человеку читать все эти лямбда-функции...
7 апреля 2025
как правило это читается намного легче, потому что кода меньше
Vitalii Shevchenko Уровень 1
19 марта 2025
Стирання типів — це процес, під час якого загальні (generic) типи стираються під час компіляції, і в байт-коді залишаються лише об'єктні типи (Object або межові типи). Це зроблено для збереження зворотної сумісності з версіями Java до 5, коли generics ще не існували.
Anonymous #3495578 Уровень 26
22 февраля 2025
А по мне так, очень увлекательно изложен материал по лямбдам. Спасибо разработчикам, делали с душой! Я лично испытал приятные эмоции интересной "по нарастающей" подачи вариантов записи и сокращения), так сказать, распробовал на вкус этот ваш синтаксический сахарок 🤝
Yasin Akhmadov Уровень 22
21 февраля 2025
В каждой лекции бывает или новая тема, или углубление в пройденной на том же уровне теме. И я заметил, что с каждым новым уровнем и лекцией нужно изучать всё больше недостающей теории и лезть в документации. Я совсем не знаком со стиранием типов и ссылками на конструкторы/методы. Информации о лямбда-функциях было явно недостаточно. Изучил этот вопрос с лямбда-выражениями вдоль и поперёк, вернулся, а тут это…