Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a Java lambda-expression reference itself?

Tags:

lambda

java-8

I found this article to be very informative in comparison of old-style functions to new Java-8 lambda-functions and parallel processing. One thing I couldn't quite understand was one restriction on the lambda-functions: From page 4:

3.3 Preconditions Although lambda expressions are intended as a more con- cise alternative to AIC , they are not a complete replacement. There are several preconditions that LambdaFicator checks before refactoring an AIC into a lambda expression. These preconditions are inherent to how lambda expressions are implemented in Java, not limitations of our tool. (P1) AIC must instantiate from an interface. Instances of abstract or concrete classes cannot be converted to lambda expressions. (P2) AIC must have no fields, and declare only one method. A lambda expression represents a single anonymous func- tion; therefore, an AIC with multiple methods can not be converted to a single lambda expression. (P3) AIC must not have references to this or super . In a lambda expression, this and super are lexically scoped, meaning they are interpreted just as they would be in the enclosing environment, e.g., as if they appeared in the state- ment before the lambda expression [6]. However, in an AIC they refer to the inner class itself. (P4) AIC must not declare a recursive method. In order to perform the recursive call, we must obtain a reference to the anonymous function. While LambdaFicator could perform this refactoring, this could introduce unneeded complexity into the code and harm understandability.

On P4, "AIC must not declare a recursive method... LambdaFicator could perform this refactoring...", how could one refactor a lambda expression to reference itself? Since by definition these lambda anonymous-functions don't have a name that can be referenced, and don't have a reference to themselves (P3 above).?

like image 489
NoBugs Avatar asked Jan 04 '15 04:01

NoBugs


People also ask

How do Java lambda expressions work?

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.

What is a lambda reference?

In C++11 and later, a lambda expression—often called a lambda—is a convenient way of defining an anonymous function object (a closure) right at the location where it's invoked or passed as an argument to a function.

What is difference between lambda expression and method reference in Java?

Lambda expression is an anonymous method (method without a name) that has used to provide the inline implementation of a method defined by the functional interface while a method reference is similar to a lambda expression that refers a method without executing it.

Can we use lambda expression without functional interface in Java?

You do not have to create a functional interface in order to create lambda function.


3 Answers

public class Test {
    static Runnable r;

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

The Runnable obtains a reference to itself from the field r when it is run.

You could also use a length 1 array to store the reference if you don't like adding a field.

like image 64
Alex - GlassEditor.com Avatar answered Nov 04 '22 17:11

Alex - GlassEditor.com


As said here, Java’s canonical way to implement a recursive function is a method:

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

Then, if you need a instance fulfilling a functional interface you can use a method reference:

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

or

IntUnaryOperator fib0=MyClass::fib;

This is the closest equivalent to a lambda expression as a lambda expression is not just syntactic sugar for a runtime generated class replacing the anonymous inner class but also for an anonymous method hosting the code of the single abstract method to implement.

Using an ordinary recursive method turns the anonymous method into a named one while maintaining all other properties of lambda expressions. This differs from all other workarounds trying to give a lambda expression a reference to itself, like storing the instance into a field. These workarounds are not semantically equivalent (and less efficient).

like image 37
Holger Avatar answered Nov 04 '22 18:11

Holger


Derived from @Alex's answer:

@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();
  }
}
like image 20
srborlongan Avatar answered Nov 04 '22 17:11

srborlongan