2015-11-06 86 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))。 –