Ссылка на метод в 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;
5 ответов
вот ведь getMaxSpeed
метод Function<Car, Integer>
.
а именно:
<Car, Integer> Comparator<Car> java.util.Comparator.comparing(
Function<? super Car, ? extends Integer> keyExtractor
)
Примечание
для справки getMaxSpeed
из экземпляра Car
С ::
идиома, вам придется объявить Car
метод с подписью: getMaxSpeed(Car car)
.
если вы хотите создать ссылку на метод для метода, который не принимает параметров, таких как метод, уже привязанный к экземпляру, вы должны использовать Supplier
, а не Function
:
Function<Car, Integer> f1 = Car::getMaxSpeed;
Car carx = new Car(42);
Supplier<Integer> f2 = carx::getMaxSpeed;
в методе reference carX::getMaxSpeed
в "неявные" this
-параметр функции уже привязан к carx
, таким образом, у вас остается функция без параметров (которая, кстати, не может быть использована в Comparator
), а в Java 8 функция без параметров-это просто Supplier
.
аналогично, если у вас есть метод, который возвращает void
, вы в конечном итоге с помощью Comsumer
:
Consumer<Integer> f3 = carx::setMaxSpeed;
функции-члена без параметров на самом деле имеет скрытый параметр,this
ссылка. Ссылки на метод формы ClassName::memberFunction
всегда используйте первый параметр функционального типа для экземпляра класса, т. е. скрытый экземпляр . Итак, в случае Car.getMaxSpeed()
, внутренне он имеет те же параметры, что и static Integer getMaxSpeed(Car car)
. будет соответствовать функциональному типу Function<Car,Integer>
, так как static Integer getMaxSpeed(Car car)
будет.
что-то подобное происходит с членом функции, которые принимают один параметр--они соответствуют BiFunction
функциональный тип, причем первым параметром является экземпляр класса.
назначение:
Function<Void, Integer> function = carX::getMaxSpeed;
не компилируется, потому что это Supplier<Integer>
, а не Function
.
тогда почему это компилируется?:
Comparator.comparing(Car::getMaxSpeed)
Java 8 позволяет ссылку на метод экземпляра, который является Supplier<U>
быть обеспеченным где Function<T, U>
ожидается, и компилятор эффективно преобразует метод getter в функцию.
чтобы узнать, почему это возможно, давайте посмотрим, как мы вызываем метод getter, используя отражение:
System.out.println(Car.class.getMethod("getMaxSpeed").invoke(carX)); // "155"
при вызове invoke()
в методе экземпляра мы передаем экземпляр в invoke()
метод геттера Method
- существует подразумеваемый параметр типа экземпляра. Когда мы смотрим на это таким образом, мы видим, что под капотом геттер действительно реализован как Function<T, U>
через invoke()
метод.
давайте посмотрим на функции подробнее:
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);
это не имеет смысла. Вы хотите пройти пустоту, чтобы применить функцию пустоты ?
несколько иллюстративных примеров того, что компилируется как функция
отметим, что c->c.getMaxSpeed()
и Car::getMaxSpeed
синтаксически эквивалентны, если метод является instanceMethod. Для non-static-methods первый аргумент выводится из типа, в котором используется метод who, и должен быть предоставлен позже (как экземпляр, на котором метод будет выполняться/применяться).
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));
}
}