为何Java中Lambda正常执行但匿名类实现会抛出StackOverflowError?
问题
我正在理解Java的Consumer接口,因此自行实现了一个类似的接口。但在将andThen()方法返回语句中的Lambda表达式替换为匿名类定义后,程序抛出了StackOverflowError:
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"); } }
请问为何Lambda表达式可正常执行,而对应的匿名类定义却会抛出StackOverflowError?
原因分析
核心差异在于方法调用的上下文指向不同:
- Lambda版本中,
accept(t)调用的是调用andThen方法的外部Interface实例(也就是e1)的accept方法。Lambda在andThen方法的上下文中创建,默认捕获了外部实例的引用,执行时会先运行e1的逻辑,再运行after(也就是e2)的逻辑,不会出现递归。 - 匿名类版本中,重写的
accept方法里的accept(t)没有指定调用对象,默认是调用当前匿名类对象自己的accept方法,这就导致了无限递归调用:每次调用这个匿名类的accept,都会再次调用自己,不断压入栈帧,最终触发StackOverflowError。
如果要修复匿名类的问题,需要明确指定调用外部实例的accept方法,修改为:
Interface.this.accept(t);
这样就能和Lambda版本的逻辑一致,先执行外部实例(e1)的accept,再执行after(e2)的accept。
内容的提问来源于stack exchange,提问作者mrinmoy saha
相关产品推荐
相关产品推荐

