Ответ
Ссылка на метод (method reference) — это компактная запись лямбда-выражения для вызова уже существующего метода. Она передаёт метод как аргумент в функциональный интерфейс, улучшая читаемость кода.
Четыре вида ссылок на методы:
- Ссылка на статический метод:
ClassName::staticMethodName - Ссылка на метод экземпляра конкретного объекта:
objectReference::instanceMethodName - Ссылка на метод экземпляра произвольного объекта:
ClassName::instanceMethodName - Ссылка на конструктор:
ClassName::new
Пример: преобразование лямбды в ссылку на метод
List<String> names = Arrays.asList("Anna", "Bob", "John");
// Лямбда-выражение:
names.forEach(s -> System.out.println(s));
// Эквивалентная ссылка на метод (более лаконично):
names.forEach(System.out::println);
Почему это работает? Метод println совместим с функциональным интерфейсом Consumer<String>, который ожидает метод с сигнатурой void accept(T t). Компилятор автоматически связывает вызов.
Ответ 18+ 🔞
А, ну вот, опять эти ваши ссылки на методы, ебушки-воробушки! Сидишь такой, пишешь лямбду, а тебе говорят: «Да ты что, мудила, это же можно в два раза короче сделать!». И правда, можно, если не лениться.
Смотри, суть-то проще пареной репы, хоть и звучит как заклинание древних. Ссылка на метод — это просто короткий способ сказать: «Вот этот готовый метод, вот сюда его и вставь, вместо всей этой лямбда-писанины». Как будто ты показываешь пальцем на уже существующий кусок кода и говоришь: «Работай, падла!».
И видов этих ссылок, на самом деле, всего четыре, не овердохуища:
- На статик метод:
ИмяКласса::статическийМетод. Тут всё ясно, как божий день. Класс и метод, который к нему прибит гвоздями. - На метод конкретного объекта:
объект::егоМетод. Тыкаешь в уже созданную переменную и говоришь: «Вот этот чувак, вот его метод, пусть работает». - На метод ЛЮБОГО объекта типа:
ИмяКласса::методЭкземпляра. Вот тут уже интереснее, хитрая жопа. Ты не указываешь конкретный объект, а говоришь: «Любой объект этого класса, у него есть такой метод, вот его и вызови, когда понадобится». Компилятор сам догадается, что к чему. - На конструктор:
ИмяКласса::new. Ну, тут вообще пиздец как просто. «Создай мне новый объект, вот по этому шаблону».
Теперь смотри, как это в жизни выглядит. Вот у тебя список имён, и ты хочешь их все вывести.
List<String> names = Arrays.asList("Anna", "Bob", "John");
// Писал раньше, как честный, но ленивый человек:
names.forEach(s -> System.out.println(s));
// А потом узнал про ссылки и пишешь так, как будто ты хипстер-программист:
names.forEach(System.out::println);
Видишь разницу? Вторая строчка — это и есть ссылка на метод. Ты говоришь: «forEach, слушай сюда, для каждого элемента вызывай не какую-то анонимную хрень, а конкретно метод println у конкретного объекта System.out».
А почему это, блядь, вообще работает? Да потому что компилятор — не дурак, он видит, что forEach ждёт на вход Consumer<String>. А у этого интерфейса есть один метод — void accept(T t). И он смотрит на System.out.println(String s), и такой: «О, ёпта! Да это же один в один! Сигнатуры совпадают — принимает строку, возвращает void. Значит, можно подставить!». И подставляет. Волшебства, блядь, ноль, чистая механика.
Вот и вся магия. Вместо того чтобы писать стрелочку и тело, ты просто указываешь на уже готовый кусок логики. Код чище, мозг свободнее, и можно пойти выпить кофе, вместо того чтобы разглядывать лишние символы.