Java 8:方法引用Bound Receiver和UnBound Receiver之间的区别
我试图在我的代码中使用Java 8方法引用。 有四种类型的方法参考可用。
- 静态方法参考。
- 实例方法(绑定接收器)。
- 实例方法(UnBound接收器)。
- 构造函数参考。
使用Static method reference
和Constructor reference
我没有问题,但Instance Method (Bound receiver)
和Instance Method (UnBound receiver)
确实让我很困惑。 在Bound
接收器中,我们使用Object引用变量来调用方法,如:
objectRef::Instance Method
在UnBound
接收器中,我们使用类名来调用方法,如:
ClassName::Instance Method.
我有以下问题:
- 实例方法的不同类型的方法引用需要什么?
-
Bound
和Unbound
接收方法引用之间有什么区别? - 我们应该在哪里使用
Bound
接收器?我们应该在哪里使用Unbound
接收器?
我还从Java 8语言特性书中找到了Bound
和Unbound
接收器的解释,但仍然与实际概念混淆。
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::instanceMethod
( arg0
是ClassName
类型)
(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]`