使用方法引用与 lambda 时,堆栈跟踪的可导航性是否较低?
Are stack traces less navigable when using method references vs lambdas?
我刚刚在 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/1681433494.apply(Unknown Source)
at java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:193)
虽然跟踪的末尾(未显示)确实 link 返回到使用 findFirst
的行,但没有返回到使用方法引用的行。
lamdba 堆栈跟踪开始时
java.lang.RuntimeException
at com.example.StackTractTest$Nasty.toInt(StackTractTest.java:11)
at com.example.StackTractTest.lambda[=12=](StackTractTest.java:26)
at com.example.StackTractTest$$Lambda/1681433494.apply(Unknown Source)
at java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:193)
正确识别第 26 行使用的 lambda。
这是 Eclipse 编译器的特性,还是在使用方法引用和 lambda 之间进行选择时应考虑的普遍缺点?
不 - 事实上你会更清楚。
at com.example.StackTractTest.lambda[=10=](StackTractTest.java:26)
行出现在 lambda 版本中这一事实提醒您,lambda 是为该技术创建的,而使用方法引用不会创建任何东西额外的
lambda是在运行时创建的,方法引用可以在编译时构造。
不,目前是这样实现的。
引用 a paper Brian Goetz 撰写的有关 lambda 表达式翻译的文章:
When the compiler encounters a lambda expression, it first lowers (desugars) the lambda body into a method whose argument list and return type match that of the lambda expression
...
Method references are treated the same way as lambda expressions, except that most method references do not need to be desugared into a new method; we can simply load a constant method handle for the referenced method and pass that to the metafactory.
你的两个堆栈跟踪之间的唯一区别是带有显式 lambda 的堆栈跟踪添加了这一行:
at com.example.StackTractTest.lambda[=10=](StackTractTest.java:26)
这是因为lambda被javac
翻译成一个新生成的方法,你可以在stacktrace中实际看到这个新方法是lambda[=12=]
.
使用方法引用,不需要生成新方法,因为它直接引用现有方法。
我刚刚在 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/1681433494.apply(Unknown Source)
at java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:193)
虽然跟踪的末尾(未显示)确实 link 返回到使用 findFirst
的行,但没有返回到使用方法引用的行。
lamdba 堆栈跟踪开始时
java.lang.RuntimeException
at com.example.StackTractTest$Nasty.toInt(StackTractTest.java:11)
at com.example.StackTractTest.lambda[=12=](StackTractTest.java:26)
at com.example.StackTractTest$$Lambda/1681433494.apply(Unknown Source)
at java.util.stream.ReferencePipeline.accept(ReferencePipeline.java:193)
正确识别第 26 行使用的 lambda。
这是 Eclipse 编译器的特性,还是在使用方法引用和 lambda 之间进行选择时应考虑的普遍缺点?
不 - 事实上你会更清楚。
at com.example.StackTractTest.lambda[=10=](StackTractTest.java:26)
行出现在 lambda 版本中这一事实提醒您,lambda 是为该技术创建的,而使用方法引用不会创建任何东西额外的
lambda是在运行时创建的,方法引用可以在编译时构造。
不,目前是这样实现的。
引用 a paper Brian Goetz 撰写的有关 lambda 表达式翻译的文章:
When the compiler encounters a lambda expression, it first lowers (desugars) the lambda body into a method whose argument list and return type match that of the lambda expression
...
Method references are treated the same way as lambda expressions, except that most method references do not need to be desugared into a new method; we can simply load a constant method handle for the referenced method and pass that to the metafactory.
你的两个堆栈跟踪之间的唯一区别是带有显式 lambda 的堆栈跟踪添加了这一行:
at com.example.StackTractTest.lambda[=10=](StackTractTest.java:26)
这是因为lambda被javac
翻译成一个新生成的方法,你可以在stacktrace中实际看到这个新方法是lambda[=12=]
.
使用方法引用,不需要生成新方法,因为它直接引用现有方法。