[英]Is defaulting to an empty lambda better or worse than checking for a potentially null lambda?
I'm working on a small scene graph implementation in Java 8. The basic scene node looks something like this: 我正在研究Java 8中的小型场景图实现。基本场景节点看起来像这样:
public class SceneNode {
private final List<SceneNode> children = new ArrayList<>();
protected Runnable preRender;
protected Runnable postRender;
protected Runnable render;
public final void render() {
preRender.run();
render.run();
for (Renderable child : children) {
child.render();
}
postRender.run();
}
}
This works fine if the Runnables
default to () -> {}
. 如果
Runnables
默认为() -> {}
这可以正常工作。 However, alternatively I could allow them to be null, but that means that render()
method has to look like this: 但是,或者我可以允许它们为null,但这意味着
render()
方法必须如下所示:
public final void render() {
if (null != preRender) { preRender.run(); }
if (null != render) { render.run(); }
for (Renderable child : children) {
child.render();
}
if (null != postRender) { postRender.run(); }
}
So my question is, is the implicit cost of the branching introduced by the null check likely to cost more or less than whatever the JVM ends up compiling an empty lambda into? 所以我的问题是,null检查引入的分支的隐式成本是否可能比JVM最终编译空lambda的成本更高或更低? It seems like it should end up costing more to check for null, because a potential branch limits optimization, while presumably the Java compiler or JVM should be smart enough to compile an empty lambda into a no-op.
看起来它应该花费更多来检查null,因为潜在的分支限制了优化,而可能是Java编译器或JVM应该足够聪明以将空lambda编译成no-op。
Interestingly, it seems that checking for null is a little bit faster , than calling an empty lambda or an empty anonymous class, when the JVM is run with the -client
argument. 有趣的是 ,当使用
-client
参数运行JVM时, 检查null似乎比调用空lambda或空匿名类快一点 。 When running with -server
, the performance is the same for all approaches. 使用
-server
运行时,所有方法的性能都相同。
I have done a micro benchmark with Caliper , to test this. 我用Caliper做了一个微基准测试。
Here is the test class (latest Caliper form git necessary to compile): 这是测试类(编译时需要的最新Caliper表单git):
@VmOptions("-client")
public class EmptyLambdaTest {
public Runnable emptyLambda = () -> {};
public Runnable emptyAnonymousType = new Runnable() {
@Override
public void run() {}
};
public Runnable nullAbleRunnable;
@Benchmark
public int timeEmptyLambda(int reps){
int dummy = 0;
for (int i = 0; i < reps; i++) {
emptyLambda.run();
dummy |= i;
}
return dummy;
}
@Benchmark
public int timeEmptyAnonymousType(int reps){
int dummy = 0;
for (int i = 0; i < reps; i++) {
emptyAnonymousType.run();
dummy |= i;
}
return dummy;
}
@Benchmark
public int timeNullCheck(int reps){
int dummy = 0;
for (int i = 0; i < reps; i++) {
if (nullAbleRunnable != null) {
nullAbleRunnable.run();
}
dummy |= i;
}
return dummy;
}
}
And here are the benchmark results: 以下是基准测试结果:
Is defaulting to an empty lambda better or worse than checking for a potentially null lambda?
违反一个空的lambda比检查一个潜在的null lambda更好还是更差?
This is essentially the same as asking if it is better to test for a null String
parameter or try to substitute an empty String
. 这与询问是否更好地测试null
String
参数或尝试替换空String
一样基本相同。
The answer is that it depends on whether you want to treat the null
as a programming error ... or not. 答案是,这取决于您是否要将
null
视为编程错误......或者不是。
My personal opinion is that unexpected null
s should be treated as programming errors, and that you should allow the program to crash with an NPE. 我个人认为, 意外的
null
应该被视为编程错误,并且你应该允许程序与NPE崩溃。 That way, the problem will come to your attention earlier and will be easier to track down and fix ... than if you substituted some "make good" value to stop the NPE from being thrown. 这样,问题就会提前引起你的注意,并且更容易追踪和修复......而不是你用一些“做好”的价值来阻止NPE被抛出。
But of course, that doesn't apply for expected null
values; 但是,当然,这不适用于预期的
null
值; ie when the API javadocs say that a null
is a permissible value, and say what it means. 即,当API javadocs说
null
是允许值时,并说出它意味着什么。
This also relates to how you design your APIs. 这也与您设计 API的方式有关。 In this case, the issue is whether your API spec (ie the javadoc!) should insist on the programmer providing a no-op lambda, or treat
null
as meaning the same thing. 在这种情况下,问题是你的API规范(即javadoc!)是否应该坚持程序员提供no-op lambda,或者将
null
视为同一个东西。 That boils down to a compromise between: 归结为以下两者之间的妥协:
I'm more concerned about the implications of the runtime performance of using an empty lambda vs using a null and having to do a null check.
我更关心使用空lambda与使用null并且必须进行空检查的运行时性能的含义。
My intuition is that testing for null
would be faster, but any difference in performance will be small, and that the chances are that it won't be significant to the overall performance of the application. 我的直觉是测试
null
会更快,但性能上的任何差异都会很小,并且很可能它对应用程序的整体性能不会很重要 。
( UPDATE - Turns out that my intuition is "half right" according to @Balder's micro-benchmarking. For a -client
mode JVM, null checking is a bit faster, but not enough to be concerning. For a -server
mode JVM, the JIT compiler is apparently optimizing both cases to native code with identical performance.) (UPDATE -原来,我的直觉是根据@巴尔德的微标杆“说对了一半”对于一个。
-client
模式JVM,空检查是有点快,但还不足以描述有关对于一个。 -server
模式JVM中, JIT编译器显然将两种情况都优化为具有相同性能的本机代码。)
I suggest that you treat that you would (or at least should ) treat any potential optimization problem: 我建议你认为你会(或至少应该 )处理任何潜在的优化问题:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.