Оператор двойного двоеточия (::) в Java 8
Я изучал исходный код Java 8 и нашел одну часть кода, которая показалась мне довольно удивительной:
// Определено в IntPipeline.java
@Override
public final OptionalInt reduce(IntBinaryOperator op) {
return evaluate(ReduceOps.makeInt(op));
}
@Override
public final OptionalInt max() {
return reduce(Math::max); // Это строка с подводным камнем
}
// Определено в Math.java
public static int max(int a, int b) {
return (a >= b) ? a : b;
}
Я хотел бы уточнить: является ли Math::max
чем-то вроде указателя на метод? Как обычный static
метод преобразуется в IntBinaryOperator
?
5 ответ(ов)
::
— это новый оператор, добавленный в Java 8, который используется для ссылки на метод существующего класса. Вы можете ссылаться как на статические, так и на нестатические методы класса.
Для ссылки на статические методы синтаксис будет следующим:
ClassName::methodName
Для ссылки на нестатические методы используется следующий синтаксис:
objRef::methodName
или
ClassName::methodName
Единственным условием для ссылки на метод является то, что метод должен существовать в функциональном интерфейсе, который должен быть совместим с указанной ссылкой на метод.
Ссылки на методы, когда они оцениваются, создают экземпляр функционального интерфейса.
Эту информацию можно найти на сайте: http://www.speakingcs.com/2014/08/method-references-in-java-8.html
:: известен как ссылка на метод. Допустим, мы хотим вызвать метод calculatePrice класса Purchase. Тогда мы можем записать это как:
Purchase::calculatePrice
Эта конструкция также может рассматриваться как сокращённая форма записи лямбда-выражения, так как ссылки на методы преобразуются в лямбда-выражения.
В более старых версиях Java, вместо использования ::
или лямбда-выражений, вы можете воспользоваться анонимными классами или создавать обычные классы. Например:
public interface Action {
void execute();
}
public class ActionImpl implements Action {
@Override
public void execute() {
System.out.println("execute with ActionImpl");
}
}
public static void main(String[] args) {
Action action = new Action() {
@Override
public void execute() {
System.out.println("execute with anonymous class");
}
};
action.execute();
// или
Action actionImpl = new ActionImpl();
actionImpl.execute();
}
Также можно передать реализацию интерфейса в метод, например так:
public static void doSomething(Action action) {
action.execute();
}
Таким образом, даже в более старых версиях Java, вы можете реализовать интерфейсы и передавать их в методы, используя как анонимные классы, так и конкретные реализации.
Да, действительно, return reduce(Math::max);
не эквивалентно return reduce(max());
.
Ваш код с использованием лямбда-функции:
IntBinaryOperator myLambda = (a, b) -> { return (a >= b) ? a : b; }; // 56 нажатий клавиш
return reduce(myLambda);
действительно требует 56 нажатий клавиш.
Однако, вы можете сэкономить 47 нажатий, если использовать метод ссылки:
return reduce(Math::max); // Всего 9 нажатий клавиш
Использование ссылки на метод Math::max
гораздо короче и удобнее, а также улучшает читаемость кода.
В Java 8 редуктор потоков (Streams Reducer) представляет собой функцию, которая принимает два значения на вход и возвращает результат после определенных вычислений. Этот результат передается в следующую итерацию.
В случае функции Math:max метод не перестает возвращать максимальное из двух переданных значений, и в итоге вы получаете наиболее крупное число.
Как определить, содержится ли определенное значение в массиве в Java?
Сортировка ArrayList пользовательских объектов по свойству
Как установить Java 8 на Mac
Java 8: Преобразование List<V> в Map<K, V>
Как работают сервлеты? Инстанцирование, сессии, общие переменные и многопоточность