11

Оператор двойного двоеточия (::) в Java 8

11

Я изучал исходный код 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 ответ(ов)

0

:: — это новый оператор, добавленный в Java 8, который используется для ссылки на метод существующего класса. Вы можете ссылаться как на статические, так и на нестатические методы класса.

Для ссылки на статические методы синтаксис будет следующим:

ClassName::methodName

Для ссылки на нестатические методы используется следующий синтаксис:

objRef::methodName

или

ClassName::methodName

Единственным условием для ссылки на метод является то, что метод должен существовать в функциональном интерфейсе, который должен быть совместим с указанной ссылкой на метод.

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

Эту информацию можно найти на сайте: http://www.speakingcs.com/2014/08/method-references-in-java-8.html

0

:: известен как ссылка на метод. Допустим, мы хотим вызвать метод calculatePrice класса Purchase. Тогда мы можем записать это как:

Purchase::calculatePrice

Эта конструкция также может рассматриваться как сокращённая форма записи лямбда-выражения, так как ссылки на методы преобразуются в лямбда-выражения.

0

В более старых версиях 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, вы можете реализовать интерфейсы и передавать их в методы, используя как анонимные классы, так и конкретные реализации.

0

Да, действительно, 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 гораздо короче и удобнее, а также улучшает читаемость кода.

0

В Java 8 редуктор потоков (Streams Reducer) представляет собой функцию, которая принимает два значения на вход и возвращает результат после определенных вычислений. Этот результат передается в следующую итерацию.

В случае функции Math:max метод не перестает возвращать максимальное из двух переданных значений, и в итоге вы получаете наиболее крупное число.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь