Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive lambda expressions in Java 8

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?

like image 843
Thomas Darimont Avatar asked Aug 11 '14 21:08

Thomas Darimont


People also ask

Can a lambda function be recursive?

This is an example of a function that will recursively call itself. Warning It's possible to run into infinite loops with recursive calls. Test your functions locally before deploying to production.

Is lambda expressions introduced in Java 8?

Lambda expressions are a new and important feature included in Java SE 8. They provide a clear and concise way to represent one method interface using an expression. Lambda expressions also improve the Collection libraries making it easier to iterate through, filter, and extract data from a Collection .

What is the type of lambda expression in Java 8?

Lambda Expressions were added in Java 8. A lambda expression is a short block of code which takes in parameters and returns a value. Lambda expressions are similar to methods, but they do not need a name and they can be implemented right in the body of a method.


2 Answers

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?

like image 105
DaoWen Avatar answered Oct 07 '22 22:10

DaoWen


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
like image 27
Matthew I. Avatar answered Oct 07 '22 23:10

Matthew I.