Java 默认为空lambda比检查可能为空的lambda好还是坏?
我正在用Java8开发一个小的场景图实现。“基本场景”节点如下所示:Java 默认为空lambda比检查可能为空的lambda好还是坏?,java,lambda,java-8,Java,Lambda,Java 8,我正在用Java8开发一个小的场景图实现。“基本场景”节点如下所示: public class SceneNode { private final List<SceneNode> children = new ArrayList<>(); protected Runnable preRender; protected Runnable postRender; protected Runnable render; public final void r
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();
}
}
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(); }
}
所以我的问题是,空检查引入的分支的隐式成本是否比JVM最终编译空lambda的成本高或低?看起来检查null的代价应该更高,因为潜在的分支限制了优化,而Java编译器或JVM应该足够聪明,能够将空lambda编译成no-op
默认为空lambda比检查可能为空的lambda好还是坏
这与询问是否最好测试空字符串
参数或尝试替换空字符串
基本相同
答案是,这取决于您是否希望将null
视为编程错误。。。或者不是
我个人的观点是,意外的null
s应该被视为编程错误,并且应该允许程序与NPE一起崩溃。这样,问题会更早地引起您的注意,并且更容易跟踪和修复。。。如果你替换了一些“makegood”值来阻止NPE被抛出
但当然,这并不适用于预期的null
值;i、 e.当API javadocs说anull
是允许的值时,并说明其含义
这还与如何设计API有关。在这种情况下,问题在于您的API规范(即javadoc!)是否应该坚持程序员提供no-op lambda,或者将
null
视为具有相同的含义。这归结为以下两者之间的折衷:
- API客户端的便利性
- API实现者工作,以及
- 稳健性;e、 g.当使用未正确初始化的变量值时
我更关心的是使用空lambda与使用null以及必须执行null检查的运行时性能的影响 我的直觉是,测试
null
会更快,但性能上的任何差异都会很小,而且很可能对应用程序的整体性能影响不大
(更新-结果证明我的直觉是“正确的一半”根据@Balder的微观基准测试。对于-client
模式的JVM,空检查稍微快一点,但还不足以令人担忧。对于-server
模式的JVM,JIT编译器显然在优化这两种情况,使之成为性能相同的本机代码。)
我建议您处理您会(或至少应该)处理任何潜在的优化问题:
有趣的是,当JVM使用
-client
参数运行时,检查null似乎比调用空lambda或空匿名类快一点。使用-server
运行时,所有方法的性能都相同
为了测试这一点,我已经用做了一个微基准测试
以下是测试类(编译所需的最新git格式):
@VmOptions(“-client”)
公共类EmptyLambdaTest{
公共可运行emptyLambda=()->{};
public Runnable emptyAnonymousType=new Runnable(){
@凌驾
public void run(){}
};
公共可运行nullAbleRunnable;
@基准
公共int TIMEMPTYLAMBDA(int代表){
int-dummy=0;
对于(int i=0;i
以下是基准结果:
null
。相信Java会用空的可运行程序做正确的事情。@LouisWasserman如果你对“正确的事情”的定义是抛出一个NullPointerException,那么是的。我认为他的观点是永远不允许它们为null,因为他明确地指的是空的可运行程序。我必须同意Erwin的观点。Java支持空周期。即使使用可选选项也不检查它是草率的。这是一个完全合法的代码行。可选fubar=null;所以,任何告诉你不需要检查NULL的人都是一个不了解真实世界的白板开发人员。这不是我想要的。当然,对于公共API,返回null和返回空值之间的区别是,或者至少可以是,关于API语义的决定。我在这里问的是不同的。这些字段是内部实现的一部分,在客户端未提供任何操作的情况下,是否填充“preRender”取决于我和我自己。我更关心的是使用空lambda与使用空lambda以及必须执行空检查的运行时性能的影响。如果您要要求使用空lambda,最好还提供以下内容:
@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;
}
}