Jhe*_*ico 10 java lambda java-8
我正在研究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();
}
}
Run Code Online (Sandbox Code Playgroud)
如果Runnables默认为,这工作正常() -> {}.但是,或者我可以允许它们为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(); }
}
Run Code Online (Sandbox Code Playgroud)
所以我的问题是,null检查引入的分支的隐式成本是否可能比JVM最终编译空lambda的成本更高或更低?看起来它应该花费更多来检查null,因为潜在的分支限制了优化,而可能是Java编译器或JVM应该足够聪明以将空lambda编译成no-op.
Bal*_*der 11
有趣的是,当JVM与-client参数一起运行时,检查null似乎比调用空lambda或空匿名类要快一点.运行时-server,所有方法的性能都相同.
我用Caliper做了一个微基准测试.
这是测试类(编译时需要的最新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;
}
}
Run Code Online (Sandbox Code Playgroud)
以下是基准测试结果:
违反一个空的lambda比检查一个潜在的null lambda更好还是更差?
这与询问是否更好地测试空String参数或尝试替换空值基本相同String.
答案是,这取决于你是否要处理null的编程错误......与否.
我个人认为,应该将意外的 null s视为编程错误,并且应该允许程序与NPE崩溃.这样,问题就会提前引起你的注意,并且更容易追踪和修复......而不是你用一些"做好"的价值来阻止NPE被抛出.
但当然,这不适用于预期 null值; 即,当API javadocs说a null是允许值时,并说出它意味着什么.
这也与您设计 API的方式有关.在这种情况下,问题是你的API规范(即javadoc!)是否应该坚持程序员提供no-op lambda,或者视为null同一个东西.归结为以下两者之间的妥协:
我更关心使用空lambda与使用null并且必须进行空检查的运行时性能的含义.
我的直觉是测试null会更快,但性能上的任何差异都会很小,并且可能性对于应用程序的整体性能而言并不重要.
(更新 - 根据@Balder的微基准测试,证明我的直觉是"一半".对于-client模式JVM,空检查要快一点,但不足以引起关注.对于-server模式JVM,JIT编译器显然是将两种情况优化为具有相同性能的本机代码.)
我建议你认为你会(或至少应该)处理任何潜在的优化问题:
| 归档时间: |
|
| 查看次数: |
5640 次 |
| 最近记录: |