2016-06-03 3 views
12
public class Car { 

    private int maxSpeed; 

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

    public int getMaxSpeed() { 
     return maxSpeed; 
    } 
} 

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

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; 
+0

Какая ошибка компилятора? –

+0

Ошибка '' Невозможно разрешить метод'. Я пробовал оба: Car :: getMaxSpeed ​​и carX :: getMaxSpeed ​​ –

+2

Я копирую/вставляю код, он работает на моей стороне, кажется, проблема с IDE –

ответ

10

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

А именно:

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

Примечание

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

+1

Но ОП задает вопрос о 'carX :: getMaxSpeed', а не' Car :: getMaxSpeed', т. Е. Метод, уже привязанный к экземпляру. –

+1

@tobias_k добавляет комментарий в мой ответ ... – Mena

+0

, хотя getMaxSpeed ​​() не принимает параметр, он отливается к 'Function '? –

9

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

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

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

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

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

Consumer<Integer> f3 = carx::setMaxSpeed; 
+1

Согласен. Проблема в том, что вы не можете использовать его в вызове 'Comparator.comparing'. ** edit ** это, вероятно, * не * проблема, учитывая контекст, на самом деле. – Mena

1

Назначение:

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

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

Итак, почему это компилировать ?:

Comparator.comparing(Car::getMaxSpeed) 

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

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

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

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

+0

ссылка или пример для последнего заявления? – HopefullyHelpful

+0

@HopefullyHelpful Пример собственного кода OP. Метод getter является поставщиком, но 'Comparator.comparing()' ожидает 'Function'. Когда тип экземпляра поставщика соответствует типу параметра ожидаемой функции, метод поставщика принимается как функция. – Bohemian

+0

В ответ вампиры отвечают, что это неверно. Или, по крайней мере, не убедительный пример. – HopefullyHelpful

3

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

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

0

Давайте посмотрим на 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);Applies this function to the given argument.

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

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

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

к сведению, что c->c.getMaxSpeed() и Car::getMaxSpeed синтаксически эквивалентными, если метод является instanceMethod. Для нестатических методов первый аргумент выводится из метода who, который используется, и его необходимо предоставить позже (в качестве экземпляра, который будет выполняться методом 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)); 
    } 
} 
Смежные вопросы