[英]Is defaulting to an empty lambda better or worse than checking for a potentially null lambda?
我正在研究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();
}
}
如果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(); }
}
所以我的問題是,null檢查引入的分支的隱式成本是否可能比JVM最終編譯空lambda的成本更高或更低? 看起來它應該花費更多來檢查null,因為潛在的分支限制了優化,而可能是Java編譯器或JVM應該足夠聰明以將空lambda編譯成no-op。
有趣的是 ,當使用-client
參數運行JVM時, 檢查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;
}
}
以下是基准測試結果:
違反一個空的lambda比檢查一個潛在的null lambda更好還是更差?
這與詢問是否更好地測試null String
參數或嘗試替換空String
一樣基本相同。
答案是,這取決於您是否要將 null
視為編程錯誤......或者不是。
我個人認為, 意外的 null
應該被視為編程錯誤,並且你應該允許程序與NPE崩潰。 這樣,問題就會提前引起你的注意,並且更容易追蹤和修復......而不是你用一些“做好”的價值來阻止NPE被拋出。
但是,當然,這不適用於預期的 null
值; 即,當API javadocs說null
是允許值時,並說出它意味着什么。
這也與您設計 API的方式有關。 在這種情況下,問題是你的API規范(即javadoc!)是否應該堅持程序員提供no-op lambda,或者將null
視為同一個東西。 歸結為以下兩者之間的妥協:
我更關心使用空lambda與使用null並且必須進行空檢查的運行時性能的含義。
我的直覺是測試null
會更快,但性能上的任何差異都會很小,並且很可能它對應用程序的整體性能不會很重要 。
(UPDATE -原來,我的直覺是根據@巴爾德的微標桿“說對了一半”對於一個。 -client
模式JVM,空檢查是有點快,但還不足以描述有關對於一個。 -server
模式JVM中, JIT編譯器顯然將兩種情況都優化為具有相同性能的本機代碼。)
我建議你認為你會(或至少應該 )處理任何潛在的優化問題:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.