Java lambda表达式如何引用自身?

时间:2015-01-04 04:48:41

标签: lambda java-8

我发现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)。?

3 个答案:

答案 0 :(得分:2)

public class Test {
    static Runnable r;

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

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

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

答案 1 :(得分:1)

来自@ 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();
  }
}

答案 2 :(得分:1)

正如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表达式引用自身的所有其他变通方法不同,例如将实例存储到字段中。这些变通方法在语义上并不等效(效率较低)。