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

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

JAVA 25 SELF
21 уровень , 1 лекция
Открыта

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 лекция
Недоступна
Фабрика виртуальных питомцев 🐾
Фабрика виртуальных питомцев 🐾
Комментарии (14)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Victor Уровень 23
9 июля 2026
Сам всё решил, кроме последней задачи, не досмотрел что в reference передаётся Animal, а я с маниакальным упорством совал туда String - сам виноват надо внимательнее смотреть.
Nikolay Karyaev Уровень 36
22 июня 2026
"Более понятный код и компактный" Мозгожевательный это код, компактный конечно, но убийственный
Олег Уровень 30
12 мая 2026
изложен материал ужасно.
qaruller Уровень 22
14 января 2026
Эта тема заставила меня задуматься о том, правильно ли я выбрал Java как свой язык
Gans Electro Уровень 28
28 июня 2026
Ушли учить старый курс, прошли до 22. Передумали? Попробуйте пройти игры. После них сильно мотивация появляется
Riga Уровень 37
3 декабря 2025
я решил задачи, но нифига не понял все равно, да и лекция мутная какая-то...
Юрий Уровень 26
27 ноября 2025
Не смотря на то, что я уже знаком с java, данная лекция абсолютно изложена непонятным языком. Не говоря уже о задачах. НУжно как-то поменять подход к данной теме, чтобы не было каши в голове
Амин Уровень 66
2 ноября 2025
а это нормально если я вообще не понимаю ни одной задачи? Откуда берутся эти apply, IntFunction? Их объяснения не было в предыдущих лекциях
Ioanna Polyak Уровень 44
5 ноября 2025
Согл
Александр Уровень 50
7 ноября 2025
Предполагаю, что это будет разжевываться дальше. Сейчас, видимо, стоит задача ознакомиться с синтаксисом и привыкнуть к нему. Глубоко погружаться не нужно, можно зависнуть на месяцы. Хотя, конечно, напрямую от разработчиков хотелось бы узнать, по какому принципу выстроено обучение.
Xaxatumba Уровень 38
13 ноября 2025
Да очередное упущение. Это один из функциональных интерфейсов пакета java.util.function. Посмотреть полный перечень можно по ссылке. И открыв любой можно увидеть какой там используется метод.
Andrey Mityakin Уровень 3
16 января 2026
Разжевывалось?
Александр Уровень 50
20 января 2026
Только на 48 и 49 уровнях объясняется функциональное программирование. Но используется регулярно, начиная с текущего уровня. Странный подход. Я бы, конечно, сначала уделил внимание основам функционального программирования, чтобы осознанно использовать его при работе с коллекциями и потоками (Stream API). Поэтому забежал вперед, чтобы ознакомиться с этими уровнями. Там несложно для понимания, но нужно свыкнуться-сработаться.
19 июня 2026
Я сам понимаю не до конца, но могу сказать, что нужно открыть сами реализации паттернов и тогда будет понятно названия методов к которым привязываются функции Вот пример для run из Runnable