Ссылки на методы
Иногда уже есть метод, который осуществляет именно те действия, которые вы хотели бы передать в другое место. Например, предположим, что вы просто хотите распечатать объект события event, когда кнопка нажата. Конечно, вы могли бы вызвать
button.setOnAction(event -> System.out.println(event));
Было бы лучше, если бы вы могли просто передать метод println в метод setOnAction. Примерно так:
button.setOnAction(System.out::println);
Выражение System.out::println является ссылкой на метод, который эквивалентен лямбда-выражению x -> System.out.println(x). В качестве другого примера, предположим, что вы хотите отсортировать строки независимо от регистра букв. Вы можете написать такой код:
Arrays.sort(strs, String::compareToIgnoreCase)
Как вы можете видеть из этих примеров оператор :: отделяет имя метода от имени объекта или класса. Есть три основных варианта:
object::instanceMethod
Class::staticMethod
Class::instanceMethod
В первых двух случаях ссылка на метод эквивалентна лямбда-выражению, которое предоставляет параметры метода. Как уже упоминалось, System.out::println эквивалентно x -> System.out.println(x). Точно так же, Math::pow эквивалентно (x, y) -> Math.pow(x, y). В третьем случае первый параметр становится целевым объектом метода. Например , String::compareToIgnoreCase - это то же самое, что и (x, y) -> x.compareToIgnoreCase(y).
При наличии нескольких перегруженных методов с тем же именем компилятор попытается найти из контекста, какой вы имеете в виду. Например, есть два варианта метода Math.max, один для int и один для double. Какой из них будет вызван, зависит от параметров метода функционального интерфейса, к которому Math.max преобразуется. Так же, как и лямбда-выражения, ссылки на методы не живут в изоляции. Они всегда преобразуются в экземпляры функциональных интерфейсов.
Вы можете захватить параметр this в ссылке на метод. Например, this::equals – это то же, что и x -> this.equals(x). Можно также использовать super. Выражение super::instanceMethod использует this в качестве цели и вызывает версию данного метода суперкласса. Вот искусственный пример, который демонстрирует механизм:
class Speaker {
public void speak() {
System.out.println("Hello, world!");
}
}
class ConcurrentSpeaker extends Speaker {
public void speak() {
Thread t = new Thread(super::speak);
t.start();
}
}
При запуске потока вызывается его Runnable, и super::speak выполняется, вызывая speak суперкласса. (Обратите внимание, что во внутреннем классе вы можете захватить эту ссылку из класса приложения, как EnclosingClass.this::method или EnclosingClass.super::method.)
Do'stlaringiz bilan baham: |