【问题标题】:How can a Java lambda-expression reference itself?Java lambda 表达式如何引用自身?
【发布时间】:2015-01-04 04:48:41
【问题描述】:

我发现this article 在比较旧式函数与新的 Java-8 lambda 函数和并行处理时提供了非常丰富的信息。我不太明白的一件事是对 lambda 函数的一个限制:从第 4 页开始:

3.3 前提条件 尽管 lambda 表达式旨在作为一种更复杂的 cise 替代 AIC ,它们不是完全替代品。 有几个前提条件 LambdaFicator 支票 在重构之前 AIC 变成一个 lambda 表达式。这些 先决条件是 lambda 表达式的固有条件 用 Java 实现,不受我们工具的限制。 (P1) AIC 必须从接口实例化。的实例 抽象或具体类不能转换为 lambda 表达式。 (P2) AIC 必须没有字段,并且只声明一个方法。 一个 lambda 表达式代表一个匿名函数 化;因此,一个 AIC 不能用多种方法 转换为单个 lambda 表达式。 (P3) AIC 不得引用 这 要么 极好的 .在 一个 lambda 表达式, 这 和 极好的 是词法范围的, 意味着它们被解释为就像它们在 封闭环境,例如,好像它们出现在状态中- 在 lambda 表达式 [6] 之前替换。然而,在一个 AIC 它们指的是内部类本身。 (P4) AIC 不得声明递归方法。为了 执行递归调用,我们必须获得对 匿名函数。尽管 LambdaFicator 可以执行 这种重构,这可能会引入不必要的复杂性 进入代码并损害可理解性。

在 P4 上,“AIC 不得声明递归方法... LambdaFicator 可以执行此重构...”,如何重构 lambda 表达式以引用自身?因为根据定义,这些 lambda 匿名函数没有可以引用的名称,也没有对自身的引用(上面的 P3)。?

【问题讨论】:

  • 天哪,是时候切换到 C#了

标签: lambda java-8


【解决方案1】:
public class Test {
    static Runnable r;

    public static void main(String... args) {
        r = () -> r.run();
        r.run();
    }
}

Runnable 在运行时从字段r 获取对自身的引用。

如果您不喜欢添加字段,也可以使用长度为 1 的数组来存储引用。

【讨论】:

    【解决方案2】:

    正如here 所说,Java 实现递归函数的规范方式是方法

    public static int fib(int n) {
        return n==0? 0: n==1? 1: fib(n-1)+fib(n-2);
    }
    

    然后,如果您需要一个实现 功能 interface 的实例,您可以使用方法引用:

    Function<Integer, Integer> fib = MyClass::fib;
    

    IntUnaryOperator fib0=MyClass::fib;
    

    这是与 lambda 表达式最接近的等价物,因为 lambda 表达式不仅是运行时生成的类替换匿名内部类的语法糖,而且是托管要实现的单个抽象方法的代码的匿名方法。

    使用普通的递归方法可以将匿名方法转换为命名方法,同时保留 lambda 表达式的所有其他属性。这不同于所有其他尝试为 lambda 表达式提供对其自身的引用的解决方法,例如将实例存储到字段中。这些变通方法在语义上并不等效(而且效率较低)。

    【讨论】:

      【解决方案3】:

      源自@Alex 的回答:

      @FunctionalInterface
      public interface SelfRunnable extends Runnable {
        public void run(SelfRunnable this_);
      
        @Override
        public default void run() {
          run(this);
        }
      
        public static Runnable runnable(SelfRunnable runnable) {
          return runnable;
        }
      }
      
      public interface Test {
        public static void main(String... arguments) {
          final Runnable r = SelfRunnable.runnable(this_ -> this_.run());
          r.run();
        }
      }
      

      【讨论】:

        【解决方案4】:

        您总是可以将 lambda 扩展为一个类:

        // Fails as r is not final and even not available upon construction of lambda:
        Runnable r = () -> { r.run(); }
        
        Runnable r = new Runnable() {
            public void run() {
                if (!stopCondition) {
                    // this naturally points to Runnable object, not the enclosing
                    this.run();
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-11-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多