Search code examples
javafunctional-interface

Lambda expression executes correctly but anonymous class definition throws error


I am trying to understand the Consumer interface of Java. I have replicated it. But it throws StackOverflowError when i replace the lambda expression in return statement of andThen() method with anonymous class definition:

interface Interface<T> {
       
    void accept(T t);

    default Interface<T> andThen(Interface<T> after) {

           //return (T t)->{accept(t); after.accept(t);};//this runs correctly
           
          //below is the anonymous class definition of above lambda expression
          return new Interface<T>(){

            @Override
            public void accept(T t)
            {
                accept(t); //stackoverflow error thrown
                after.accept(t);
            }
          };
     }
}

//Main class:

public class Lambda2 {

    public static void main(String args[]) {
        Interface<String> e1=str -> System.out.println("in e1 - "+str);
    
        Interface<String> e2=str -> System.out.println("in e2 - "+str);
        
        Interface<String> e3 = e1.andThen(e2);
        
        e3.accept("Sample Output");
    }
}

Could you please let me know why the lambda expression of the anonymous class definition does not cause StackOverflowError?


Solution

  • You can find the reason for this in JLS 15.27.2 (my emphasis):

    Unlike code appearing in anonymous class declarations, the meaning of names and the this and super keywords appearing in a lambda body, along with the accessibility of referenced declarations, are the same as in the surrounding context (except that lambda parameters introduce new names).

    That is, the name accept inside the lambda body has the same meaning as the accept outside the lambda body; and the difference is an anonymous class is explicitly called out.

    So: calling accept in a lambda defined the body of the andThen method will involve the accept method on the instance (just as if you had invoked accept directly in the method body); whereas calling accept in the body of the accept method in the anonymous class will recursively invoke itself.