Подтвердить что ты не робот

Ссылка на метод в Java 8

public class Car {

    private int maxSpeed;

    public Car(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }

    public int getMaxSpeed() {
        return maxSpeed;
    }
}

Мы можем сортировать список автомобилей,

    Car carX = new Car(155);
    Car carY = new Car(140);

    List<Car> cars = new ArrayList<>();
    cars.add(carX);
    cars.add(carY);

    cars.sort(Comparator.comparing(Car::getMaxSpeed));

Если мы видим сигнатуру метода Comparator.comparing, входной тип параметра Function<? super T, ? extends U>

В приведенном выше примере, как Car::getMaxSpeed применяется к Function<? super T, ? extends U>, а следующее не компилируется?

  Function<Void, Integer> function = Car::getMaxSpeed;
4b9b3361

Ответ 1

Это потому, что метод getMaxSpeed является Function<Car, Integer>.

А именно:

<Car, Integer> Comparator<Car> java.util.Comparator.comparing(
    Function<? super Car, ? extends Integer> keyExtractor
)

Примечание

Чтобы ссылаться на getMaxSpeed из экземпляра Car с помощью идиомы ::, вам нужно объявить метод Car с сигнатурой: getMaxSpeed(Car car).

Ответ 2

Если вы хотите создать ссылку метода для метода, который не принимает никаких параметров, таких как метод, уже привязанный к экземпляру, вы должны использовать Supplier, а не Function:

Function<Car, Integer> f1 = Car::getMaxSpeed;

Car carx = new Car(42);
Supplier<Integer> f2 = carx::getMaxSpeed; 

В методе reference carX::getMaxSpeed "неявный" this -параметр функции уже привязан к carx, поэтому вы остаетесь с функцией no-parameter (которая, кстати, может не используется в Comparator), а в Java 8 функция no-parameter - это просто Supplier.

Аналогично, если у вас есть метод, который возвращает void, вы получите Comsumer:

Consumer<Integer> f3 = carx::setMaxSpeed;

Ответ 3

Функция-член без параметров имеет скрытый параметр, ссылку this. В ссылках метода формы ClassName::memberFunction всегда используется первый параметр функционального типа для экземпляра класса, т.е. Скрытый параметр this. Итак, в случае Car.getMaxSpeed(), внутри он имеет те же параметры, что и static Integer getMaxSpeed(Car car). Таким образом, Car::getMaxSpeed будет соответствовать функциональному типу Function<Car,Integer>, точно так же, как a static Integer getMaxSpeed(Car car).

Что-то подобное происходит с функциями-членами, которые принимают один параметр - они соответствуют функциональному типу BiFunction, причем первым параметром является экземпляр класса.

Ответ 4

Назначение:

Function<Void, Integer> function = carX::getMaxSpeed;

не компилируется, потому что это a Supplier<Integer>, а не Function.

Итак, зачем эта компиляция?:

Comparator.comparing(Car::getMaxSpeed)

Java 8 позволяет указать ссылку на метод экземпляра Supplier<U>, где ожидается Function<T, U>, и компилятор эффективно преобразует метод getter в функцию.

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

System.out.println(Car.class.getMethod("getMaxSpeed").invoke(carX)); // "155"

При вызове invoke() метода экземпляра мы передаем экземпляр методу invoke() метода getter Method - там подразумевается параметр типа экземпляра. Когда мы смотрели на это так, мы видим, что под капотом геттер действительно реализован как Function<T, U> с помощью метода invoke().

Ответ 5

Подробно рассмотрите Function:

Interface Function<T,R> {

    default <V> Function<T,V>   andThen(Function<? super R,? extends V> after){}

    R   apply(T t);

    default <V> Function<V,R>   compose(Function<? super V,? extends T> before){}

    static <T> Function<T,T>    identity();

}

отметить R apply(T t); Применяет эту функцию к данному аргументу.

Function<Void, Integer> function = Void::?????;
Void voidInstance = null;
function.apply(voidInstance);

Это не имеет смысла. Вы хотите передать Void, чтобы применить функцию Void?

Несколько иллюстративных примеров того, что компилируется как функция

обратите внимание, что c->c.getMaxSpeed() и Car::getMaxSpeed являются синтаксически эквивалентными, если метод является методом экземпляра. Для нестатических методов первый аргумент выводится из типа, для которого используется метод, и его необходимо предоставить позже (в качестве экземпляра, который будет выполняться методом on/apply on).

public class Car {

    private int maxSpeed;

    public Car(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }

    public int getMaxSpeed() {
        return this.maxSpeed;
    }
    public Void setMaxSpeed() {
        this.maxSpeed = 12;
        return null;
    }
    public static int intStaticFunction(Void v) {
        return new Random().nextInt();
    }
    public static Void voidStaticFunction(Void v) {
        return null;
    }
    public static void main(String[] args) {
        final Car carX = new Car(155);
        final Car carY = new Car(140);

        final List<Car> cars = new ArrayList<>();
        cars.add(carX);
        cars.add(carY);

        cars.sort(Comparator.comparing(Car::getMaxSpeed));
        final Function<Car, Integer> function1 = c->c.getMaxSpeed();
        final Function<Car, Integer> function2 = Car::getMaxSpeed;
        final Function<Car, Void> function3 = Car::setMaxSpeed;
        final Function<Void, Void> function4 = n->n;
        final Function<Void, Integer> function5 = n->5;
        final Function<Void, Integer> function6 = Car::intStaticFunction;
        final Function<Void, Void> function7 = Car::voidStaticFunction;
        final Function<Car, Integer> function8 = function1::apply;
        final Function<Car, Integer> function9 = function2::apply;
        System.out.println(function1.apply(carX));
        System.out.println(function2.apply(carX));
        System.out.println(function8.apply(carX));
        System.out.println(function9.apply(carX));
        System.out.println(function3.apply(carX));
        System.out.println(function1.apply(carX));
        System.out.println(function2.apply(carX));
        System.out.println(function8.apply(carX));
        System.out.println(function9.apply(carX));
        System.out.println();
        System.out.println(function4.apply(null));
        System.out.println(function5.apply(null));
        System.out.println(function6.apply(null));
        System.out.println(function7.apply(null));
    }
}