我刚刚在Eclipse中进行了快速实验。
public class StackTractTest {
static class Nasty {
public Integer toInt() {
if (1 == 1) throw new RuntimeException();
return 1;
}
}
@Test
public void methodReference() {
Stream.of(new Nasty())
.map(Nasty::toInt)
.findFirst();
}
@Test
public void lambda() {
Stream.of(new Nasty())
.map(n -> n.toInt())
.findFirst();
}
}
当方法参考测试失败时,跟踪开始
java.lang.RuntimeException
at com.example.StackTractTest$Nasty.toInt(StackTractTest.java:11)
at com.example.StackTractTest$$Lambda$1/1681433494.apply(Unknown Source)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
虽然跟踪的末尾(未显示)确实链接回findFirst
上的行,但没有对使用方法引用的行的引用。
lamdba stacktrace开始时
java.lang.RuntimeException
at com.example.StackTractTest$Nasty.toInt(StackTractTest.java:11)
at com.example.StackTractTest.lambda$0(StackTractTest.java:26)
at com.example.StackTractTest$$Lambda$1/1681433494.apply(Unknown Source)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
正确识别lambda用于第26行。
这是Eclipse编译器的特性还是这是使用方法引用的一般缺点,在选择它们和lambda时应该考虑这些引用?
答案 0 :(得分:4)
不,这就是目前的实施方式。
引用Brian Goetz撰写的关于lambda表达式翻译的a paper:
当编译器遇到lambda表达式时,它首先将lambda体降低(desugars)为一个方法,其参数列表和返回类型与lambda表达式匹配
...
方法引用的处理方式与lambda表达式相同,不同之处在于大多数方法引用不需要被置于新方法中;我们可以简单地为引用的方法加载一个常量方法句柄,并将其传递给metafactory。
两个堆栈跟踪之间的唯一区别是具有显式lambda的那个已经添加了这一行:
at com.example.StackTractTest.lambda$0(StackTractTest.java:26)
这是因为lambda由javac
翻译成新生成的方法,你实际上可以在stacktrace中看到这个新方法是lambda$0
。
使用方法引用,不必生成新方法,因为它直接引用现有方法。
答案 1 :(得分:2)
不 - 实际上你会更清晰。
lambda版本中出现at com.example.StackTractTest.lambda$0(StackTractTest.java:26)
行的事实提醒您,对于此技术,已创建,而使用方法引用时不会创建任何额外的内容。
lambda是在运行时创建的,方法引用可以在编译时构造。