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

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

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

Четыре формы

ClassName::staticMethod         // статический метод
object::instanceMethod          // метод конкретного объекта
ClassName::instanceMethod       // метод произвольного объекта данного типа
ClassName::new                  // конструктор

Примеры

Пример 1. Ссылка на статический метод

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class StaticRef {
    public static void main(String[] args) {
        Function<String, Integer> parse = Integer::parseInt;
        List<String> raw = Arrays.asList("12", "8", "25");
        for (String s : raw) {
            System.out.println(parse.apply(s) + 1);
        }
    }
}

Output:

13
9
26

Пример 2. Ссылка на метод конкретного объекта

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class BoundRef {
    public static void main(String[] args) {
        List<String> events = Arrays.asList("старт", "стоп", "пауза");
        Consumer<String> printer = System.out::println;
        events.forEach(printer);
    }
}

Output:

старт
стоп
пауза

Пример 3. Ссылка на метод произвольного объекта типа

import java.util.Arrays;
import java.util.List;

public class UnboundRef {
    public static void main(String[] args) {
        List<String> sensors = Arrays.asList("ик", "Линия", "УЗ");
        sensors.stream()
               .map(String::toUpperCase)
               .forEach(System.out::println);
    }
}

Output:

ИК
ЛИНИЯ
УЗ

Пример 4. Ссылка на конструктор

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class ConstructorRef {
    static class Sensor {
        final String name;
        Sensor(String name) { this.name = name; }
        @Override public String toString() { return "Sensor(" + name + ")"; }
    }

    public static void main(String[] args) {
        List<String> names = Arrays.asList("ИК", "УЗ", "Линия");
        List<Sensor> sensors = names.stream()
                                    .map(Sensor::new)
                                    .collect(Collectors.toList());
        System.out.println(sensors);
    }
}

Output:

[Sensor(ИК), Sensor(УЗ), Sensor(Линия)]

Пример 5. Сортировка с Comparator.comparing

import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

public class CompareRef {
    public static void main(String[] args) {
        List<String> items = Arrays.asList("робот", "ИК", "ультразвук", "LED");
        items.sort(Comparator.comparing(String::length));
        System.out.println(items);
    }
}

Output:

[ИК, LED, робот, ультразвук]

Подводные камни

Предупреждение

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

  • У перегруженных методов компилятору может не хватить контекста — придётся вернуться к лямбде с явными типами параметров.

  • ClassName::instanceMethod принимает экземпляр класса первым аргументом. Это удобно для stream().map(String::toUpperCase), но иногда сбивает с толку.

  • У object::method объект захватывается один раз — если ссылка хранится долго, объект тоже будет жить.

См. также

Примечание

Материал подготовлен по мотивам Oracle Java Tutorials (Method References) и распространяется в рамках Oracle Free Documentation License. Текст написан своими словами, примеры кода — оригинальные.