我正在尝试在我的代码中使用Java 8方法引用。有四种类型的方法参考可用。
使用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 language features books找到了对Bound
和Unbound
接收器的解释,但仍然与实际概念相混淆。
答案 0 :(得分:16)
像String::length
这样的unBound接收器的想法是你指的是
对象的方法将作为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 Book
中从Java 8中退出的答案答案 1 :(得分:9)
基本上,未绑定的接收器允许您使用实例方法,就好像它们是具有声明类型的第一个参数的静态方法一样 - 因此您可以通过传入任何您想要的实例来将它们用作函数。使用绑定接收器," target"实例实际上是函数的一部分。
一个例子可能会更清楚:
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<String> supplier = t2::method;
Function<Test, String> 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;
}
}
答案 2 :(得分:3)
如果希望为某个类的特定实例执行该方法,则使用绑定接收器。
例如:
Stream.of("x","y").forEach(System.out::println);
将在println
- PrintStream
实例的特定实例上执行System.out
。因此,System.out.println("x")
和System.out.println("y")
会在将该方法引用传递给forEach
时执行。
另一方面,如果您希望为未指定的类实例执行该方法,则可以使用未绑定的接收器。
例如:
Stream.of("x","y","").filter(String::isEmpty);
将在流的每个isEmpty()
个实例上执行String
- 即"x".isEmpty()
,"y".isEmpty()
和"".isEmpty()
。
答案 3 :(得分:0)
伴随着上面的优秀答案。 感谢joshua bloch的精彩解释,有效的java第三版。我终于能够绕过有界和无界的参考手段。
在有界引用中,接收对象在方法中指定 参考。绑定引用在本质上与静态类似 引用:函数对象采用与。相同的参数 参考方法。
在未绑定的引用中,接收对象在指定时指定 函数对象通过前面的附加参数应用 方法的声明参数。未绑定的引用通常用作 流管道中的映射和过滤功能
最后,对于类,有两种构造函数引用 和数组。构造函数引用充当工厂对象。
`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<K,V>::new | () -> new TreeMap
Array
Constructor | int[]::new | len -> new int[len]`
答案 4 :(得分:0)
答案 5 :(得分:0)
这是一个例子:
public static void main(String[] args) {
// unbound
UnaryOperator<String> u = String::toUpperCase;
System.out.println(u.apply("hello"));
// bound
String a = "hello";
Supplier<String> r = a::toUpperCase;
System.out.println(r.get());
}
这将输出两行HELLO
。