【问题标题】:Can a lambda access members of its target functional interface?lambda 可以访问其目标功能接口的成员吗?
【发布时间】:2015-02-28 10:39:05
【问题描述】:

我使用 java8 创建了一个简单的接口。因为它包含一种方法和一种默认方法。

interface Lambda{

default void dummy(){
    System.out.println("Call this..");
}

void yummy();
}

我正在尝试使用类似的历史方式来使用这两种方法

public class DefaultCheck {

public static void main(String[] args) {

    DefaultCheck check = new DefaultCheck();
    check.activate(new Lambda() {

        @Override
        public void yummy() {
            dummy();
        }
    });

}

void activate(Lambda lambda){
    lambda.yummy();
}

}

现在我正在尝试使用 lambda 表达式来实现同样的事情,得到类似 `dummy is undefined` 的错误

check.activate(() -> {
        dummy();
    });

任何人都可以建议,如何使用 Lambda 表达式来实现这个场景?

【问题讨论】:

  • 作为记录,IntelliJ 不建议用 lambda 替换匿名类的用法,尽管如果 yummy() 不调用 dummy() 会这样做。也许这是不可能的。
  • 请注意,这与默认方法没有太大关系;它更多的是关于名称“this”的含义,在这种情况下,它被隐式使用。

标签: java lambda java-8


【解决方案1】:

如果我理解正确的话。您正在尝试通过 lambda 实现调用接口中的默认方法。我觉得可以。

@FunctionalInterface
interface Value 
{
    String init(Value a);


    default String add(String b) 
    {
        return "added content "+b;
    }


    default String getResult()
    {
        String c = init(this);
        return c;
    }
}

public class Main
{


    public static void main(String[] args)
    {

        Value v = a -> a.add("inpout"); // here I am calling add method in Value interface.
        String c = v.getResult();

        System.out.println(c);

    }
}

【讨论】:

    【解决方案2】:

    内部类实现工作,因为代码被调用,就像你编码一样:

    check.activate(new Lambda() {
      @Override
      public void yummy() {
        this.dummy();
      }
    });
    

    我们现在的问题是 lambdas 没有引入新的作用域。因此,如果您希望您的 lambda 能够引用自身,您可以优化您的 @FunctionalInterface 以便其函数方法接受自身及其所需参数:

    check.activate(this_ -> this_.dummy());
    

    其中 Lambda 定义为:

    @FunctionalInterface
    public interface Lambda {
      void yummy(Lambda this_);
    
      default void yummy() {
        yummy(this);
      }
    
      default void dummy(){
        System.out.println("Call this..");
      }
    }
    

    【讨论】:

      【解决方案3】:

      做不到。

      JLS 15.27.2 解决这个问题:

      与匿名类声明中出现的代码不同, 名称以及出现在 lambda 正文中的 this 和 super 关键字, 与引用声明的可访问性一起,是相同的 与周围环境一样(除了 lambda 参数引入 新名称)。

      this 在主体中的透明度(显式和隐式) lambda 表达式 - 也就是说,将其视为与 周围的上下文 - 为实现提供更大的灵活性,并且 防止正文中不合格名称的含义 依赖于重载决议。

      实际上,lambda 表达式需要 谈论自己(递归地调用自己或调用它的 其他方法),但更常见的是希望使用名称来引用 封闭类中的东西,否则会被遮蔽 (这个,toString())。 如果需要 lambda 表达式 引用自身(好像通过 this)、方法引用或匿名 应该使用内部类。

      【讨论】:

      • lambda 表达式中名称的含义(包括通常隐含的名称“this”)是 JSR-335 专家组中讨论最广泛的主题之一。这两个位置可以有效地描述为“lambdas are objects”和“lambdas are functions”。最终选择了“lambdas are functions”方法;它在语义上更简单,并且允许更深入的优化。这种选择的缺点是许多用户习惯于(复杂!)内部类的语义,并且经常惊讶地发现 lambda 的工作方式并不完全相同。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-23
      • 1970-01-01
      • 1970-01-01
      • 2014-08-21
      • 1970-01-01
      • 2012-04-12
      相关资源
      最近更新 更多