Java Lambda引用Enclosing Object:用私有静态类替换? [英] Java Lambda Referencing Enclosing Object: Replace with Private Static Class?

查看:102
本文介绍了Java Lambda引用Enclosing Object:用私有静态类替换?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

引用其封闭范围中的元素的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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆