13

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?

3
  • 3
    you REALLY should'nt mix lambda with recursion - doing so pretty much assures major, unexpected or even unexplicable problems. Mixing these things is like mixing two VERY volatile chemicals, the resulting explosion will literally destroy your free time in no time at all. Commented Aug 11, 2014 at 21:52
  • 1
    I know ;-) just wanted to see whats possible :) Commented Aug 11, 2014 at 21:57
  • see my answer for the problem. You can use a 'this' variable to tackle this. stackoverflow.com/questions/19429667/… Commented Oct 17, 2019 at 9:49

3 Answers 3

12

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?

Sign up to request clarification or add additional context in comments.

3 Comments

Ah yes, this works - thanks! UnaryOperator<Integer> f = i -> i == 0 ? 1 : i * this.f.apply( i - 1); seems to be enough already for the instance field case.
@ThomasDarimont - Good to know! I assumed that this inside a lambda would refer to the lambda itself and thus cause problems, so I decided to go with RecursiveLambdaExample.this instead. I'll edit my answer.
@DaoWen: if there was a way to refer to the lambda itself, that enabled invoking it recursively without needing to access the outer variable where the lambda is stored. But lambdas cannot refer to itself, this and super have the meaning of the outer scope and a lambda can not invoke any method on the instance created for the lambda expression.
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

Comments

1

just expand your lambda to an anonymous class:

    UnaryOperator<Integer> f = new UnaryOperator<Integer>(){
        @Override
        public Integer apply(Integer i) {
            return i == 0 ? 1 : i * this.apply( i - 1);
        }
    };

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.