Что такое ссылка на метод в Java?

Ответ

Ссылка на метод (method reference) — это компактная запись лямбда-выражения для вызова уже существующего метода. Она передаёт метод как аргумент в функциональный интерфейс, улучшая читаемость кода.

Четыре вида ссылок на методы:

  1. Ссылка на статический метод: ClassName::staticMethodName
  2. Ссылка на метод экземпляра конкретного объекта: objectReference::instanceMethodName
  3. Ссылка на метод экземпляра произвольного объекта: ClassName::instanceMethodName
  4. Ссылка на конструктор: 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+ 🔞

А, ну вот, опять эти ваши ссылки на методы, ебушки-воробушки! Сидишь такой, пишешь лямбду, а тебе говорят: «Да ты что, мудила, это же можно в два раза короче сделать!». И правда, можно, если не лениться.

Смотри, суть-то проще пареной репы, хоть и звучит как заклинание древних. Ссылка на метод — это просто короткий способ сказать: «Вот этот готовый метод, вот сюда его и вставь, вместо всей этой лямбда-писанины». Как будто ты показываешь пальцем на уже существующий кусок кода и говоришь: «Работай, падла!».

И видов этих ссылок, на самом деле, всего четыре, не овердохуища:

  1. На статик метод: ИмяКласса::статическийМетод. Тут всё ясно, как божий день. Класс и метод, который к нему прибит гвоздями.
  2. На метод конкретного объекта: объект::егоМетод. Тыкаешь в уже созданную переменную и говоришь: «Вот этот чувак, вот его метод, пусть работает».
  3. На метод ЛЮБОГО объекта типа: ИмяКласса::методЭкземпляра. Вот тут уже интереснее, хитрая жопа. Ты не указываешь конкретный объект, а говоришь: «Любой объект этого класса, у него есть такой метод, вот его и вызови, когда понадобится». Компилятор сам догадается, что к чему.
  4. На конструктор: ИмяКласса::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. Значит, можно подставить!». И подставляет. Волшебства, блядь, ноль, чистая механика.

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