JavaRush/Курсы/JAVA 25 SELF/Method References (::): ссылки на методы

Method References (::): ссылки на методы

Открыта

1. Введение

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

Синтаксис:

Класс::метод
объект::метод
Класс::new

Если лямбда — это мини-функция "на лету", то method reference — это просто «передай уже имеющийся метод». Это похоже на то, как вместо переписывания рецепта вы даёте ссылку на страницу с рецептом.

Пример на пальцах

Вместо этого:

list.forEach(s -> System.out.println(s));

Можно так:

list.forEach(System.out::println);

Выглядит лаконично, не правда ли?

2. Виды method references

У ссылок на методы четыре основные формы. Вот они — и больше ничего не нужно.

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

Синтаксис: Класс::статическийМетод

Пример:

Function<Integer, String> intToString = String::valueOf;
System.out.println(intToString.apply(123)); // "123"

То же самое через лямбду:

Function<Integer, String> intToString = i -> String.valueOf(i);

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

Синтаксис: объект::метод

Пример:

PrintStream printer = System.out;
Consumer<String> consumer = printer::println;
consumer.accept("Привет, мир!");

Эквивалентно лямбде:

Consumer<String> consumer = s -> printer.println(s);

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

Синтаксис: Класс::метод

Здесь первый параметр функционального интерфейса становится объектом, на котором вызывается метод.

Пример:

Function<String, Integer> stringLength = String::length;
System.out.println(stringLength.apply("Java")); // 4

Здесь String::length превращается в функцию: (String s) -> s.length()

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

Синтаксис: Класс::new

Пример:

Supplier<ArrayList<String>> listSupplier = ArrayList::new;
ArrayList<String> list = listSupplier.get();

Эквивалентно лямбде:

Supplier<ArrayList<String>> listSupplier = () -> new ArrayList<>();

3. Когда использовать method reference?

Method reference удобно применять, когда лямбда просто вызывает существующий метод без дополнительной логики — так код становится короче и читабельнее.

Пример: сортировка списка

Вместо этого:

List<String> names = Arrays.asList("Иван", "Петр", "Анна");
names.sort((a, b) -> a.compareToIgnoreCase(b));

Можно так:

names.sort(String::compareToIgnoreCase);

Пример: обработка коллекций

Вместо:

list.forEach(s -> System.out.println(s));

Можно вообще коротко:

list.forEach(System.out::println);

Пример: преобразование элементов

Вместо:

List<String> numbers = Arrays.asList("1", "2", "3");
List<Integer> ints = numbers.stream()
    .map(s -> Integer.parseInt(s))
    .collect(Collectors.toList());

Можно:

List<Integer> ints = numbers.stream()
    .map(Integer::parseInt)
    .collect(Collectors.toList());

Подробнее про Stream API и утилитный класс Collectors вы узнаете на уровне 30 :P

4. Сравнение method reference и лямбда-выражения

Эквивалентность

Method reference и лямбда-выражение часто взаимозаменяемы. Оба реализуют функциональный интерфейс, если сигнатуры совпадают.

Пример:

Consumer<String> c1 = s -> System.out.println(s);
Consumer<String> c2 = System.out::println;

Когда лучше использовать method reference?

  • Когда лямбда просто вызывает существующий метод без дополнительной логики.
  • Для повышения читаемости, особенно при длинных цепочках вызовов.
  • Когда хочется явно показать: «здесь просто вызов метода».

Когда method reference не подходит?

  • Если нужна дополнительная логика (валидация, условия, обработка ошибок).
  • Если параметры надо преобразовать перед вызовом метода.

Пример:

list.forEach(s -> {
    if (s != null) System.out.println(s);
});
// Здесь method reference не подойдёт, только лямбда.

5. Практика: переписываем лямбда-выражения с использованием method references

Пример 1: Выводим имена животных

List<String> animals = Arrays.asList("Кот", "Собака", "Попугай");
animals.forEach(animal -> System.out.println(animal));

Становится:

animals.forEach(System.out::println);

Пример 2: Преобразуем строки в числа

List<String> numbers = Arrays.asList("10", "20", "30");
List<Integer> ints = numbers.stream()
    .map(s -> Integer.parseInt(s))
    .collect(Collectors.toList());

Становится:

List<Integer> ints = numbers.stream()
    .map(Integer::parseInt)
    .collect(Collectors.toList());

Пример 3: Сортировка объектов по имени

List<Animal> animalList = ...;
animalList.sort((a, b) -> a.getName().compareTo(b.getName()));

Становится:

animalList.sort(Comparator.comparing(Animal::getName));

Здесь Animal::getName — ссылка на нестатический метод класса.

Пример 4: Создание объектов через конструктор

Supplier<Dog> dogFactory = () -> new Dog();
Dog dog = dogFactory.get();

Становится:

Supplier<Dog> dogFactory = Dog::new;
Dog dog = dogFactory.get();

6. Как работает сопоставление сигнатур

Method reference можно использовать только тогда, когда сигнатура метода совпадает с абстрактным методом функционального интерфейса.

@FunctionalInterface
interface IntToString {
    String convert(int value);
}

public class Demo {
    public static String intToHex(int value) {
        return Integer.toHexString(value);
    }

    public static void main(String[] args) {
        IntToString converter = Demo::intToHex;
        System.out.println(converter.convert(255)); // ff
    }
}

Здесь Demo::intToHex подходит, потому что принимает int и возвращает String.

7. Method reference и конструкторы с параметрами

Если конструктор принимает параметры, method reference всё равно можно использовать — при совпадении сигнатур.

@FunctionalInterface
interface AnimalFactory {
    Animal create(String name);
}

class Animal {
    private String name;
    public Animal(String name) { this.name = name; }
    public String getName() { return name; }
}

AnimalFactory factory = Animal::new;
Animal cat = factory.create("Барсик");
System.out.println(cat.getName()); // Барсик

8. Типичные ошибки при использовании method references

Ошибка №1: Несоответствие сигнатур.
Если сигнатура метода не совпадает с абстрактным методом интерфейса, компилятор выдаст ошибку. Например, интерфейс ожидает два параметра, а ссылка указывает на метод с одним параметром.

Ошибка №2: Попытка использовать ссылку на нестатический метод класса без объекта.
Когда используете форму Класс::метод, первый параметр интерфейса становится объектом вызова. Если перепутать количество или порядок параметров — получите ошибку сопоставления.

Ошибка №3: Использование method reference там, где нужна дополнительная логика.
Если требуется условие, логирование или обработка исключений — используйте лямбду, а не ссылку на метод.

Ошибка №4: Ссылки на перегруженные методы.
Если у класса несколько методов с одинаковым именем, компилятор может не понять, какой из них выбрать. Иногда помогает явное указание типа функционального интерфейса.

Ошибка №5: Использование ссылки на нестатический метод без объекта.
Например, String::toUpperCase корректно работает в map, потому что первый параметр — сам объект String. Но вне подходящего контекста, где ожидается статический метод, это приведёт к ошибке.

1
Задача
JAVA 25 SELF,  21 уровень,  1 лекция
Недоступна
Конвертер идентификаторов устройств 📟
Конвертер идентификаторов устройств 📟
1
Задача
JAVA 25 SELF,  21 уровень,  1 лекция
Недоступна
Индивидуальная система логирования 📝
Индивидуальная система логирования 📝
1
Задача
JAVA 25 SELF,  21 уровень,  1 лекция
Недоступна
Организация инвентаря на складе 🍎🍌🍐
Организация инвентаря на складе 🍎🍌🍐
1
Задача
JAVA 25 SELF,  21 уровень,  1 лекция
Недоступна
Фабрика виртуальных питомцев 🐾
Фабрика виртуальных питомцев 🐾
Комментарии (15)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Ivan Kulazhenkov
Уровень 23
1 октября, 15:36
Удивительно, как от зоопарка мы пришли к подобным вещам p. s. ни понял ни черта
VictorThe main expert in Automa в Строительная компани
9 июля, 10:36
Сам всё решил, кроме последней задачи, не досмотрел что в reference передаётся Animal, а я с маниакальным упорством совал туда String - сам виноват надо внимательнее смотреть.
Nikolay Karyaev
Уровень 31
22 июня, 12:29
"Более понятный код и компактный" Мозгожевательный это код, компактный конечно, но убийственный
Олег
Уровень 40
12 мая, 18:07
изложен материал ужасно.
qaruller
Уровень 23
14 января, 08:22
Эта тема заставила меня задуматься о том, правильно ли я выбрал Java как свой язык
Gans Electro
Уровень 59
28 июня, 09:55
Ушли учить старый курс, прошли до 22. Передумали? Попробуйте пройти игры. После них сильно мотивация появляется
Riga Android Developer
3 декабря 2025, 12:34
я решил задачи, но нифига не понял все равно, да и лекция мутная какая-то...
Юрий
Уровень 26
27 ноября 2025, 11:31
Не смотря на то, что я уже знаком с java, данная лекция абсолютно изложена непонятным языком. Не говоря уже о задачах. НУжно как-то поменять подход к данной теме, чтобы не было каши в голове
Амин
Уровень 66
2 ноября 2025, 17:50
а это нормально если я вообще не понимаю ни одной задачи? Откуда берутся эти apply, IntFunction? Их объяснения не было в предыдущих лекциях
Ioanna Polyak
Уровень 51
5 ноября 2025, 16:58
Согл
Александр
Уровень 50
7 ноября 2025, 09:55
Предполагаю, что это будет разжевываться дальше. Сейчас, видимо, стоит задача ознакомиться с синтаксисом и привыкнуть к нему. Глубоко погружаться не нужно, можно зависнуть на месяцы. Хотя, конечно, напрямую от разработчиков хотелось бы узнать, по какому принципу выстроено обучение.
Xaxatumba
Уровень 38
13 ноября 2025, 06:25
Да очередное упущение. Это один из функциональных интерфейсов пакета java.util.function. Посмотреть полный перечень можно по ссылке. И открыв любой можно увидеть какой там используется метод.
Andrey Mityakin
Уровень 3
16 января, 15:48
Разжевывалось?
Александр
Уровень 50
20 января, 10:58
Только на 48 и 49 уровнях объясняется функциональное программирование. Но используется регулярно, начиная с текущего уровня. Странный подход. Я бы, конечно, сначала уделил внимание основам функционального программирования, чтобы осознанно использовать его при работе с коллекциями и потоками (Stream API). Поэтому забежал вперед, чтобы ознакомиться с этими уровнями. Там несложно для понимания, но нужно свыкнуться-сработаться.
19 июня, 09:09
Я сам понимаю не до конца, но могу сказать, что нужно открыть сами реализации паттернов и тогда будет понятно названия методов к которым привязываются функции Вот пример для run из Runnable