2012-01-04 6 views
6

ifステートメントになると、Javaが実際にどのように動作するのか不思議です。 (注:下の「コンポーネント」とは、明細書で確認される部分を意味します。たとえば、abcJavaがIF文と効率をどのように処理するか

どちらが計算効率が良いですか?

if (a && b && c) { do stuff } 

または

if (a) { 
    if (b) { 
    if (c) { 
    do stuff } 
    } 
} 

それはJavaが最初のバージョンで何をするかが重要ですので、私が尋ねる理由はあります。ステートメント内のすべてのものをチェックするか、aをチェックし、それがfalseである場合は、残りのステートメントのチェックをキャンセルしますか?

この場合、最も失敗する可能性が高いコンポーネントをステートメントの最初のコンポーネントとして配置することは理にかなっています。

2つ目の例のように、文全体が毎回チェックされると、コンポーネントを複数の異なる文に分割する方が理にかなっています。

+3

これを簡単に試すことができます。 – Howard

+0

私は、彼らが呼び出されるときに印刷するa、b、c関数を作っていると思いますよね? – Chro

+2

@Howard:私はものを試して大きな賛美者です。しかし、私はいくつかのコード(またはバイトコードを見て)を実行することは、短絡動作が*保証されているかどうかを確認する良い方法だとは思わない*。このために、Java言語仕様は決定的なリソースです。 – NPE

答えて

15

Javaでは、&&||は短絡が保証されています。オペランドは左から右に評価され、結果が確実にわかるとすぐに評価が停止します。 JLSから

&&オペレータは&(§15.22.2)、似ているが、その左辺オペランドの値がtrue場合にのみ、その右側のオペランドを評価します。構文的に左結合(左から右にグループ化)されています。

||演算子は、|(15.22。2)、であるが、その左側のオペランドの値が偽である場合にのみその右側のオペランドを評価する。構文的に左結合(左から右にグループ化)されています。

これは、質問の2つのコードスニペットがまったく同等であることを意味します。

5

(a && b && c)の条件付き「短絡」は、1つが失敗するとすぐに残りの部分は評価されません。

ただし、a,bcのいずれかが高価でない限り、これは時期尚早の最適化のケースである可能性があります。あなたは

if (getA() && getB() && getC())...

をすればgetA()が失敗した場合

一部または全部が高価している場合は、その後、その後、他の方法がさえ呼ばれていません。

6

これらのコードスニペットは、完全に同等であり、全く同じバイトコードを生成する:

0: iload_1 
1: ifeq 20 //a == false (0) 
4: iload_2 
5: ifeq 20 //b == false (0) 
8: iload_3 
9: ifeq 20 //c == false (0) 
12: //do stuff 
20: return 

説明は異なるが、コード生成器は、同じ出力を生成します。遅い評価による最初のケースでは、後の用語は前のものがfalseである場合に評価されません。第2のケースでは、周囲がifの条件を満たさない場合、ランタイムはより深く進まない。

+0

だから、基本的にそれは文字通り問題ではないと言っていますか? (コードの可読性を除いて) – Chro

+1

@Chro:はい、パフォーマンス面では**重要ではありません**。しかしながら、例えば'a'は時間がかかるので、それをさらに(またはより深く)押し込むことを検討して、決して評価されない可能性が高くなります。 –

3

このようなことを確認する最も良い方法は、Java Language Specificationです。この場合

、あなたはsection 15.23をしたい:

実行時に、左辺オペランド式が最初に評価されます。結果にブール型がある場合は、アンボクシング変換が行われます(5.1.8)。結果の値がfalseの場合、条件式および式の値はfalseで、右側のオペランド式は評価されません。

falseからa evalutesあればなし、表現a && b && cで、bcは評価されません。

これはifステートメントの動作の一部ではないことに注意してください。これは&&オペレータの動作の一部です。あなただけの別の場所で式を使用して同じ効果を見ることができます:

// Still won't evaluate b and c if a is false... 
boolean x = a && b && c; 

2

で(それが原因あなたが仕様を相談したいときのための言語のどの部分にあるかの行動を意識する価値があります。)最初のケースでは、iffalseの条件(短絡)で初めてfalseと評価されます。第二部も評価されるかどうNullPointerExceptionを得ることなく

if(a != null && a.toString().equals("b")) 

:そうしないとあなたのような何かをすることはできません。

+0

非常に参考に、そのような特定の事件については考えていない。良い例え。 – Chro

1
if (a && b && c) { do stuff } 

これは短絡しています。 aが偽と評価される場合、&&は短絡します。これは、残りのチェックが行われないことを意味します。

それ以外は、2つのアプローチに違いはないと思います。

+0

aはfalseと評価されます。 – Tudor

+0

偽、確かに? trueはbも評価されなければならないことを意味します - これはORではなくANDです – mcfinnigan

+0

@Tudor:そうです。 trueは '||'と一緒に行かなければなりません。ありがとう。 –

1

この:

if (condition is met) { 
     //continute to next check 
      if (condition is met) { 
       //continue to next check 
        if (condition is met) { 
    do stuff } 
    } 
} 

は同じい:if (a && b && c) { do stuff }が、スペースの多くを占めます。この特定のコードセグメントで効率を心配する必要はありません。そのため、最初のオプションを使用することが最良の方法です。また

if (a && b){ 
if (condition is met) { 
     do stuff } 
} 
1

& &とを行うことができ||短絡論理演算子です。これは、あなたの例では、aがfalseの場合、残りの式は評価されないことを意味します。

非短絡論理演算子を使用する場合は、&と|を使用できます。

あなたは確認が必要な場合は、Java言語仕様の次の文を見ることができます:http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.22.2

5

私は、コンパイラは、私は、Java 1.6を使用して、次のコードをコンパイルしたので、両方のケースを扱うだろうか興味があった:

public class IfTest 
{ 
    public static void main(String[] args) 
    { 
     IfTest iffy = new IfTest(); 
     iffy.doit(); 
    } 

    private void doit() 
    { 
     Random rand = new Random(); 
     boolean a = rand.nextBoolean(); 
     boolean b = rand.nextBoolean(); 
     boolean c = rand.nextBoolean(); 

     if (a && b && c) 
     { 
      System.out.println("block 1"); 
     } 

     if (a) 
     { 
      if (b) 
      { 
       if (c) 
       { 
        System.out.println("block 2"); 
       } 
      } 
     } 
    } 
} 

... Jadを使用して逆コンパイルします。デコンパイラがクラスファイルから生成したものを次に示します。

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. 
// Jad home page: http://www.kpdus.com/jad.html 
// Decompiler options: packimports(3) 
// Source File Name: IfTest.java 

import java.util.Random; 

public class IfTest 
{ 

    public IfTest() 
    { 
    } 

    public static void main(String args[]) 
    { 
     IfTest iffy = new IfTest(); 
     iffy.doit(); 
    } 

    private void doit() 
    { 
     Random rand = new Random(); 
     boolean a = rand.nextBoolean(); 
     boolean b = rand.nextBoolean(); 
     boolean c = rand.nextBoolean(); 
     if(a && b && c) 
      System.out.println("block 1"); 
     if(a && b && c) 
      System.out.println("block 2"); 
    } 
} 

どのように記述するかは関係ありません。

関連する問題