Java 8:方法引用Bound Receiver和UnBound Receiver之间的区别

我试图在我的代码中使用Java 8方法引用。 有四种类型的方法参考可用。

  1. 静态方法参考。
  2. 实例方法(绑定接收器)。
  3. 实例方法(UnBound接收器)。
  4. 构造函数参考。

使用Static method referenceConstructor reference我没有问题,但Instance Method (Bound receiver)Instance Method (UnBound receiver)确实让我很困惑。 在Bound接收器中,我们使用Object引用变量来调用方法,如:

 objectRef::Instance Method 

UnBound接收器中,我们使用类名来调用方法,如:

 ClassName::Instance Method. 

我有以下问题:

  1. 实例方法的不同类型的方法引用需要什么?
  2. BoundUnbound接收方法引用之间有什么区别?
  3. 我们应该在哪里使用Bound接收器?我们应该在哪里使用Unbound接收器?

我还从Java 8语言特性书中找到了BoundUnbound接收器的解释,但仍然与实际概念混淆。

unBound接收器的概念,如String::length ,是指一个对象的方法, 它将作为lambda的一个参数提供 。 例如,lambda表达式(String s) -> s.toUpperCase()可以重写为String::toUpperCase

但是Bounded指的是当您将lambda中的方法调用到已存在外部对象时的情况 。 例如,lambda表达式() -> expensiveTransaction.getValue()可以重写为expensiveTransaction::getValue

三种不同方法参考的情况

(args) -> ClassName.staticMethod(args)可以是ClassName::staticMethod

(arg0, rest) -> arg0.instanceMethod(rest)可以是ClassName::instanceMethodarg0ClassName类型)

(args) -> expr.instanceMethod(args)可以是expr::instanceMethod

从Action 8中的Java 8中退出的答案

基本上,未绑定的接收器允许您使用实例方法,就好像它们是具有声明类型的第一个参数的静态方法一样 – 因此您可以通过传入您想要的任何实例来将它们用作函数。 对于绑定接收器,“目标”实例实际上是function的一部分。

一个例子可能会使这更清楚:

 import java.util.function.*; public class Test { private final String name; public Test(String name) { this.name = name; } public static void main(String[] args) { Test t1 = new Test("t1"); Test t2 = new Test("t2"); Supplier supplier = t2::method; Function function = Test::method; // No need to say which instance to call it on - // the supplier is bound to t2 System.out.println(supplier.get()); // The function is unbound, so you need to specify // which instance to call it on System.out.println(function.apply(t1)); System.out.println(function.apply(t2)); } public String method() { return name; } } 

如果希望为某个类的特定实例执行该方法,则使用绑定接收器。

例如 :

 Stream.of("x","y").forEach(System.out::println); 

将在特定的PrintStream实例 – System.out实例上执行println 。 因此,将该方法引用传递给forEach将执行System.out.println("x")System.out.println("y")

另一方面,如果您希望为未指定的类实例执行该方法,则可以使用未绑定的接收器。

例如 :

 Stream.of("x","y","").filter(String::isEmpty); 

将在Stream的每个String实例上执行isEmpty() – 即"x".isEmpty()"y".isEmpty()"".isEmpty()

伴随着上面的优秀答案。 感谢joshua bloch的精彩解释,有效的java第三版。 我终于能够绕过有界和无界的参考手段。

在有界引用中,接收对象在方法引用中指定。 绑定引用在本质上类似于静态引用:函数对象采用与引用方法相同的参数。

在未绑定的引用中,在应用函数对象时,通过方法声明的参数之前的附加参数指定接收对象。 未绑定引用通常用作流管道中的映射和过滤function

最后,对于类和数组,有两种构造函数引用。 构造函数引用充当工厂对象。

 `Method Ref | Example | Lambda Equivalent Static | Integer::parseInt | str -> Integer.parseInt(str) Bound | Instant.now()::isAfter | Instant then = Instant.now(); | t -> then.isAfter(t) Unbound | String::toLowerCase | str -> str.toLowerCase() Class Constructor | TreeMap::new | () -> new TreeMap Array Constructor | int[]::new | len -> new int[len]`