Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

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

Часто лямбда лишь вызывает один готовый метод и передаёт ему свой параметр: s -> s.toUpperCase(), x -> IO.println(x). Такую лямбду можно записать короче — ссылкой на метод через оператор ::.

Первая ссылка на метод

Слева от :: указывают класс или объект, справа — имя метода без скобок. Обе строки ниже делают одно и то же:

void main() {
    List<String> names = List.of("Анна", "Олег");
    names.forEach(name -> IO.println(name));
    names.forEach(IO::println);
}

Результат:

Анна
Олег
Анна
Олег

Ссылка IO::println значит «вызови IO.println() с каждым элементом». Аргументы подставит сама Java. Ссылка на метод — не вызов: метод выполнится позже, когда его вызовет forEach().

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

Ссылка вида Класс::статическийМетод передаёт параметры лямбды в статический метод. Так удобно превращать строки в числа:

void main() {
    Function<String, Integer> parse = Integer::parseInt;
    BinaryOperator<Integer> add = Integer::sum;
 
    IO.println(parse.apply("42") + 1);
    IO.println(add.apply(2, 3));
}

Результат:

43
5

Метод произвольного объекта

Запись String::toUpperCase похожа на статическую, но работает иначе: первый параметр лямбды становится объектом, у которого вызывается метод. Это эквивалент s -> s.toUpperCase():

void main() {
    Function<String, String> upper = String::toUpperCase;
    Function<String, Integer> length = String::length;
 
    IO.println(upper.apply("привет"));
    IO.println(length.apply("привет"));
}

Результат:

ПРИВЕТ
6

Именно так устроены компараторы из главы о коллекциях: Comparator.comparing(Product::price) вызывает price() у каждого товара.

Метод конкретного объекта

Если слева стоит переменная, метод будет вызываться у этого объекта, а параметр лямбды станет аргументом:

void main() {
    List<String> cart = new ArrayList<>();
    Consumer<String> addToCart = cart::add;
 
    addToCart.accept("чай");
    addToCart.accept("печенье");
    IO.println(cart);
}

Результат:

[чай, печенье]

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

Класс::new — ссылка на конструктор. Она создаёт новый объект из параметров лямбды:

record User(String name) {}
 
void main() {
    Function<String, User> create = User::new;
    Supplier<List<String>> newList = ArrayList::new;
 
    IO.println(create.apply("Анна"));
    IO.println(newList.get());
}

Результат:

User[name=Анна]
[]

Частая ошибка

Ссылка на метод подходит, только если параметры и тип результата метода совпадают с функциональным интерфейсом. Например, String::length возвращает число, а Predicate ждёт boolean:

void main() {
    Predicate<String> check = String::length;
}

Результат:

Main.java:2: error: incompatible types: bad return type in method reference
    Predicate<String> check = String::length;
                              ^
    int cannot be converted to boolean

Если метод не подходит напрямую, напишите обычную лямбду: s -> s.length() > 3. Вообще ссылка на метод — не обязанность, а сокращение: выбирайте ту запись, которая читается легче.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.