2015-11-06 89 views
2

TL; Dr,滾動到最後的編輯。我將這一切都留在這裏,讓人們可以從這個討論的演變中讀到。如果在編譯/反編譯後返回null if {return}

我已經得到了一個庫下面的代碼:

private void addData(JSONObject jsonObject) { 
    if (jsonObject == null){ 
     return; 
    } 
    if (jsonObject.has("elements")){ 
     try { 
      addData(jsonObject.getJSONArray("elements")); 
     } catch (JSONException e) { 
      e.printStackTrace(); 
     } 
    }else{ 
     try { 
      getArray().put(jsonObject); 
     } catch (JSONException e) { 
     } 
    } 
} 

現在Android Studio中,我使用這個庫。當我進入它(通過按Ctrl + B去的函數的定義),我看到它,它反編譯這樣:

private void addData(JSONObject jsonObject) { 
    if(jsonObject != null) { 
     if(jsonObject.has("elements")) { 
      try { 
       this.addData(jsonObject.getJSONArray("elements")); 
      } catch (JSONException var3) { 
       var3.printStackTrace(); 
      } 

     } else { 
      try { 
       this.getArray().put(jsonObject); 
      } catch (JSONException var4) { 
       ; 
      } 

     } 
    } 
} 

我知道這有效它是相同的,但在我心中這會影響性能。我的代碼會更快,如果jsonObject經常爲空,(因爲它不必跳到功能的末尾,然後跳出來,如第二個版本所做的那樣),如果jsonObject是第二個版本,效率更高更經常地不是null

我對改變性能的聲明是否正確?Java是如何編譯它的呢?

編輯:
好了,因爲我看到一些答覆,指出這是完全一樣的,讓我再詳細一點。我有過C和C++的多門課程。這些語言會立即被翻譯成程序集,從而很容易看到所有的跳轉。

說,我們已經得到這個僞代碼:如果事情是假的

function a(){ 
    //p1 
    b(); //jump to b() 
    //p2 
} 
function b(){ 
    if (something){//if not, jump to. If, don't jump } (1st jump) 
     goto whereyoucamefrom;//whereyoucamefrom in this case is b(); in function a(), so it'll jump to p2 (1st jump) 
    } 
    goto whereyoucamefrom;//whereyoucamefrom is now also b();, so going to p2 again. (2nd jump, only when not something.) 
} 

這導致1周跳,如果事情是真實的,2:

function a(){ 
    //p 1 
    b(); 
    //p2 
} 
function b(){ 
    if (something){ 
     return; 
    } 
} 

這將被編譯成。這絕對看起來比我更有效:

function b(){ 
    if (!something){//if not, jump to else (1st jump) 
     //body of function 
     goto afterelse; 
    }else{//if the body got executed, jump to } (1st jump) 
     goto endoffunction; 
    } 


    goto whereyoucamefrom;//this is endoffunction (2nd jump, always gets executed) 
} 

這總是會導致2跳。

編輯: 好吧,我將嘗試使用此編輯來澄清(再一次)我的意圖與這篇文章。

我的問題是有關跳轉(或跳轉)級別的優化。我的問題是,是不是真的

function a(){ 
    if (something){ 
     jump out of function; 
    } 
    //body 
    jump out of function; 
} 

function a(){ 
    if (something){ 
     jump over else 
    }else{ 
     //body 
    } 
    jump out of function 
} 

更快?如果是這樣,爲什麼java編譯器不能正確執行此操作?請參閱原始帖子,瞭解我編寫的代碼和decompiled版本的編譯版本。

+0

似乎是一個很好的問題,誰下降了誰? – droidev

+0

性能應該是一樣的。你必須檢查'jsonObject'至少一次以確定它是否爲'null'。反編譯的代碼在我的oppinion中稍微好一點,因爲它只將方法留在一個分支上(不需要'return;'需要)。 – Turing85

+0

@ Turing85我知道你必須檢查是否爲null,但我也在考慮跳轉到這裏。當處理器執行時,跳轉(或跳轉)在處理器上非常昂貴,因爲它必須沖洗管道,至少需要3次,最多可達20個時鐘週期。 –

回答

2

它是微處理器一種相當常見的策略:1)使用管道,2)將在後面執行的預加載的代碼,將其變爲其內部表示,並且在一些結構中,預先執行它。分支是兩個問題,這是分支預測的關鍵。通常,對程序員來說,正確的做法是減少分支的數量,並將預期在if-then-else語句的「then」分支中運行的代碼放在最後,因爲處理器經常「下注」這會發生。

這就是說,在現實中,性能取決於一大堆非常難以預測的參數。例如,如果您的「優化」代碼被編譯爲稍長的機器代碼序列,則可能會導致緩存未命中並導致緩慢。或者它可能會導致您的更長的代碼更好地對齊,從而更快。或者別的,因爲代碼是在星期五早上運行的。

此外,您還顯示,對「編譯」的Java代碼,但對於編譯JVM的彙編代碼?如果編譯器執行流分析,它可能會檢測到「else」分支直接到該方法的末尾,並將其替換爲一個返回。或者不是,因爲它可能更有效率,但是再次,它可能不是。

當然,這一切並不甚至開始考慮到Java的在其上的一切,我上面寫的可能是錯的非常不同的架構上運行的事實。

在我看來,寫最常見的執行代碼的if-then-else塊中的「然後」分支,並避免喙代碼流,只要合理可能的線索清晰,容易閱讀的代碼。它也恰好是更高效的,所以我絕對推薦它。當然,就像所有的建議一樣,這個不應該被視爲硬性規定。

2
public void method1(JSONObject jsonObject) {  
    if (jsonObject == null){ 
     return; 
     //end 
    } 
    //do stuff 
} 

public void method2(JSONObject jsonObject) { 
    if(jsonObject != null) { 
     //do stuff 
    } 
    //end 
} 

是相同的。沒有性能差異。正如你所說,我認爲當jsonObject通常爲空時,你的代碼不會更有效率。

+0

正如我在我的編輯中詳細闡述的那樣,在'do stuff'之後的第一個方法中也需要'// end'。這會導致第二次跳轉,超過1次(第一次是'if(jsonObject == null)'**或** 2(otherwise))。 –