Java 8 中的方法参考
Method reference in 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;
那是因为getMaxSpeed
方法是一个Function<Car, Integer>
。
即:
<Car, Integer> Comparator<Car> java.util.Comparator.comparing(
Function<? super Car, ? extends Integer> keyExtractor
)
备注
为了从具有 ::
习语的 Car
的实例中引用 getMaxSpeed
,您必须声明一个带有签名的 Car
方法:getMaxSpeed(Car car)
.
如果要为不带参数的方法(例如已绑定到实例的方法)创建方法引用,则应使用 Supplier
,而不是 Function
:
Function<Car, Integer> f1 = Car::getMaxSpeed;
Car carx = new Car(42);
Supplier<Integer> f2 = carx::getMaxSpeed;
在方法引用 carX::getMaxSpeed
中,函数的 "implicit" this
参数已经绑定到 carx
,所以你剩下一个无参数-function(顺便说一句,不能在 Comparator
中使用),而在 Java 8 中,无参数函数只是 Supplier
.
同样,如果你有一个 returns void
的方法,你最终会得到一个 Comsumer
:
Consumer<Integer> f3 = carx::setMaxSpeed;
作业:
Function<Void, Integer> function = carX::getMaxSpeed;
无法编译,因为它是 Supplier<Integer>
,而不是 Function
。
那么,为什么会编译呢?:
Comparator.comparing(Car::getMaxSpeed)
Java 8 允许在需要 Function<T, U>
的地方提供 Supplier<U>
的实例方法引用,并且编译器有效地将 getter 方法转换为一个函数。
为了找出为什么这是可能的,让我们看看我们如何使用反射调用 getter 方法:
System.out.println(Car.class.getMethod("getMaxSpeed").invoke(carX)); // "155"
在实例方法上调用 invoke()
时,我们将实例传递给 getter 的 Method
的 invoke()
方法 - 有一个隐含的参数实例类型。当这样看时,我们看到在引擎盖下 getter 实际上是通过 invoke()
方法实现为 Function<T, U>
。
一个没有参数的成员函数实际上有一个隐藏参数,this
引用。 ClassName::memberFunction
形式的方法引用始终使用 class 实例的功能类型的第一个参数,即实例的隐藏 this
参数。因此,在 Car.getMaxSpeed()
的情况下,它在内部具有与 static Integer getMaxSpeed(Car car)
相同的参数。 Car::getMaxSpeed
因此适合函数类型 Function<Car,Integer>
,就像 static Integer getMaxSpeed(Car car)
一样。
带有一个参数的成员函数也会发生类似的情况——它们符合 BiFunction
函数类型,第一个参数是 class 实例。
让我们详细看一下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);
这没有意义。您想传递一个 Void 以便应用 Void 的功能?
什么是函数编译的一些说明性示例
请注意,如果方法是 instanceMethod,c->c.getMaxSpeed()
和 Car::getMaxSpeed
在语法上是等价的。对于非静态方法,第一个参数是从使用方法的类型推断出来的,需要稍后提供(作为方法将在 on/applied 上执行的实例)。
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));
}
}
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;
那是因为getMaxSpeed
方法是一个Function<Car, Integer>
。
即:
<Car, Integer> Comparator<Car> java.util.Comparator.comparing(
Function<? super Car, ? extends Integer> keyExtractor
)
备注
为了从具有 ::
习语的 Car
的实例中引用 getMaxSpeed
,您必须声明一个带有签名的 Car
方法:getMaxSpeed(Car car)
.
如果要为不带参数的方法(例如已绑定到实例的方法)创建方法引用,则应使用 Supplier
,而不是 Function
:
Function<Car, Integer> f1 = Car::getMaxSpeed;
Car carx = new Car(42);
Supplier<Integer> f2 = carx::getMaxSpeed;
在方法引用 carX::getMaxSpeed
中,函数的 "implicit" this
参数已经绑定到 carx
,所以你剩下一个无参数-function(顺便说一句,不能在 Comparator
中使用),而在 Java 8 中,无参数函数只是 Supplier
.
同样,如果你有一个 returns void
的方法,你最终会得到一个 Comsumer
:
Consumer<Integer> f3 = carx::setMaxSpeed;
作业:
Function<Void, Integer> function = carX::getMaxSpeed;
无法编译,因为它是 Supplier<Integer>
,而不是 Function
。
那么,为什么会编译呢?:
Comparator.comparing(Car::getMaxSpeed)
Java 8 允许在需要 Function<T, U>
的地方提供 Supplier<U>
的实例方法引用,并且编译器有效地将 getter 方法转换为一个函数。
为了找出为什么这是可能的,让我们看看我们如何使用反射调用 getter 方法:
System.out.println(Car.class.getMethod("getMaxSpeed").invoke(carX)); // "155"
在实例方法上调用 invoke()
时,我们将实例传递给 getter 的 Method
的 invoke()
方法 - 有一个隐含的参数实例类型。当这样看时,我们看到在引擎盖下 getter 实际上是通过 invoke()
方法实现为 Function<T, U>
。
一个没有参数的成员函数实际上有一个隐藏参数,this
引用。 ClassName::memberFunction
形式的方法引用始终使用 class 实例的功能类型的第一个参数,即实例的隐藏 this
参数。因此,在 Car.getMaxSpeed()
的情况下,它在内部具有与 static Integer getMaxSpeed(Car car)
相同的参数。 Car::getMaxSpeed
因此适合函数类型 Function<Car,Integer>
,就像 static Integer getMaxSpeed(Car car)
一样。
带有一个参数的成员函数也会发生类似的情况——它们符合 BiFunction
函数类型,第一个参数是 class 实例。
让我们详细看一下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);
这没有意义。您想传递一个 Void 以便应用 Void 的功能?
什么是函数编译的一些说明性示例
请注意,如果方法是 instanceMethod,c->c.getMaxSpeed()
和 Car::getMaxSpeed
在语法上是等价的。对于非静态方法,第一个参数是从使用方法的类型推断出来的,需要稍后提供(作为方法将在 on/applied 上执行的实例)。
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));
}
}