Java Lambda引用Enclosing Object:用私有静态类替换? [英] Java Lambda Referencing Enclosing Object: Replace with Private Static Class?
问题描述
引用其封闭范围中的元素的Java lambda持有对其封闭对象的引用。一个人为的例子,用lambda控制引用MyClass:
class MyClass {
final String foo =foo;
public Consumer< String> getFn(){
return bar - > System.out.println(bar + foo);
$ b $ p
$ b 如果lambda的生命周期很长,这是有问题的;那么我们就得到了一个长期存在的MyClass的引用,否则它将不在范围之内。在这里,我们可以通过用一个私有静态类替换lambda进行优化,以便我们只持有对我们需要的字符串的引用,而不是对整个类的引用:
class MyClass {
private static class PrintConsumer implements Consumer< String> {
String foo;
PrintConsumer(String foo){
this.foo = foo;
}
@Override
public void accept(String bar){
System.out.println(bar + foo);
}
}
final String foo =foo;
public Consumer< String> getFn(){
返回新的PrintConsumer(foo);
$ b 不幸的是,这是超级冗长的,从lambdas中使用(有效的最终)变量来封装作用域。这在技术上是最佳的吗?
首先是局部变量:
class MyClass {
final String foo =foo;
私人消费者< String> getFn(){
String localFoo = foo;
返回栏 - > System.out.println(bar + localFoo);
$ b现在,lambda只捕获 getFn()
。 MyClass.this
不再被捕获。
另一个稍微冗长的选项委托给辅助方法:
class MyClass {
final String foo =foo;
私人消费者< String> getFn(){
return getFn(foo);
}
private static Consumer< String> getFn(String localFoo){
return bar - > System.out.println(bar + localFoo);
}
}
A Java lambda referencing an element from its enclosing scope holds a reference to its enclosing object. A contrived example, with lambda holding ref to MyClass:
class MyClass {
final String foo = "foo";
public Consumer<String> getFn() {
return bar -> System.out.println(bar + foo);
}
}
This is problematic if the lifetime of the lambda is long; then we've got a ref to MyClass that is long-lived, when it would have otherwise gone out of scope. Here we can optimize by replacing the lambda with a private static class, so that we're only holding a reference to the String we need rather than to the entire class:
class MyClass {
private static class PrintConsumer implements Consumer<String> {
String foo;
PrintConsumer(String foo) {
this.foo = foo;
}
@Override
public void accept(String bar) {
System.out.println(bar + foo);
}
}
final String foo = "foo";
public Consumer<String> getFn() {
return new PrintConsumer(foo);
}
}
Unfortunately this is super verbose and destroys the nice syntax we get from using (effectively final) variables from enclosing scope in lambdas. Is this technically optimal? Is there always a tradeoff here between nice syntax and the possibility of keeping a ref longer than necessary?
解决方案 Assign your member to a local variable first:
class MyClass {
final String foo = "foo";
private Consumer<String> getFn() {
String localFoo = foo;
return bar -> System.out.println(bar + localFoo);
}
}
Now, the lambda only captures local variables inside of getFn()
. MyClass.this
is no longer captured.
Another option, slightly more verbose, delegate to a helper method:
class MyClass {
final String foo = "foo";
private Consumer<String> getFn() {
return getFn(foo);
}
private static Consumer<String> getFn(String localFoo) {
return bar -> System.out.println(bar + localFoo);
}
}
这篇关于Java Lambda引用Enclosing Object:用私有静态类替换?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!