Recursive lambda expressions in Java 8

2020-02-28 04:21发布

问题:

I just wanted to define a Java 8 lambda expression recursively.

The Lambda FAQ mentions that one can define a recursive lambda expression only during (static) field initialization.

But I get a compiler error in IntelliJ (javac just reports an error without a message):

java: self-reference in initializer

If I try to write something like:

static UnaryOperator<Integer> f = i -> i == 0 ? 1 : i * f.apply( i - 1);

or

UnaryOperator<Integer> f = i -> i == 0 ? 1 : i * f.apply( i - 1);

One way I found to make it work was to use an array for referencing the lambda effectively tricks the java compiler:

import java.util.function.UnaryOperator;

public class RecursiveLambdaExample {

    public static void main(String[] args) {

        UnaryOperator<Integer>[] fac = new UnaryOperator[1];
        fac[0] = i -> i == 0 ? 1 : i * fac[0].apply( i - 1);

        UnaryOperator<Integer> factorial = fac[0];

        System.out.println(factorial.apply(5));
    }
}

Is there another trick to define recursive lambda expression?

回答1:

You can make it work by fully-qualifying the field name that you're referencing recursively. This version compiles without any error:

import java.util.function.UnaryOperator;

public class RecursiveLambdaExample {

    static UnaryOperator<Integer> fac = i -> i == 0 ? 1 : i * RecursiveLambdaExample.fac.apply( i - 1);

    UnaryOperator<Integer> f = i -> i == 0 ? 1 : i * this.f.apply( i - 1);

    public static void main(String[] args) {
        System.out.println(new RecursiveLambdaExample().f.apply(5));
        System.out.println(fac.apply(5));
    }
}

Related: Why do lambdas in Java 8 disallow forward reference to member variables where anonymous classes don't?



回答2:

You are able to achieve this with nested class:

public class Main {

    public static void main(String[] args) {

        class Helper {
            final UnaryOperator<Integer> f = i -> i == 0 ? 1 : i * this.f.apply( i - 1);
        }

       System.out.println(new Helper().f.apply(3));
    }
}

output:

6