どちらの「if」構文が高速ですか-ステートメントまたは三項演算子?


83

ifJavaには、classic:if {} else {}とshorthand:の2種類のステートメントがありますexp ? value1 : value2。一方が他方より速いですか、それとも同じですか?

ステートメント:

int x;
if (expression) {
  x = 1;
} else {
  x = 2;
}

三項演算子:

int x = (expression) ? 1 : 2;

34
全く違いはないと思います。単なる構文です。コンパイラがやや悪(または他の何か)で、私が間違っていない限り
sinelaw 2011年

4
あなたはそれを(マイクロ)ベンチマークしましたか?結果を共有します。
BalusC 2011年

3
両方ともジッターになります。まったく違いはありません。そして、ものを逆コンパイルすることを気にしないでください。HotSpotが最初に行うことは、javacによって適用されたすべての最適化を取り除くことです。
Ivo Wetzel 2011年

11
それらは異なる速度では存在しません。それらはさまざまな目的で存在します。ステートメントと式の違いを理解していると思います。ステートメントはアクションを実行します。式は値を生成します。ifステートメントで使用するためのものです。?式で使用するためのものです。
Mike Dunlavey 2011年

3
この質問への回答は、元の質問の意図が誤っている場合でも読む価値があるため、+ 1。
jball 2011年

回答:


106

そこには「if」ステートメントのタイプが1つだけあります。もう1つは条件式です。どちらのパフォーマンスが向上するかについては、同じバイトコードにコンパイルでき、同じように動作することが期待されます。または、パフォーマンスの観点からどちらかを選択したくないほど近いものになると思います。

時にはif文は、時には条件演算子が読みやすくなり、読みやすくなります。特に、2つのオペランドが単純で副作用がない場合は条件演算子を使用することをお勧めしますが、2つの分岐の主な目的それらの副作用である場合は、おそらくifステートメントを使用します。

サンプルプログラムとバイトコードは次のとおりです。

public class Test {
    public static void main(String[] args) {
        int x;
        if (args.length > 0) {
            x = 1;
        } else {
            x = 2;
        }
    }

    public static void main2(String[] args) {
        int x = (args.length > 0) ? 1 : 2;
    }
}

で逆コンパイルされたバイトコードjavap -c Test

public class Test extends java.lang.Object {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1
       4: return

  public static void main(java.lang.String[]
    Code:
       0: aload_0
       1: arraylength
       2: ifle          10
       5: iconst_1
       6: istore_1
       7: goto          12
      10: iconst_2
      11: istore_1
      12: return

  public static void main2(java.lang.String[
    Code:
       0: aload_0
       1: arraylength
       2: ifle          9
       5: iconst_1
       6: goto          10
       9: iconst_2
      10: istore_1
      11: return
}

ご覧のとおり、ここではバイトコードにわずかな違いがあります-istore_1ブランス内で発生するかどうか(以前の非常に欠陥のある試みとは異なります:)が、JITterが異なるネイティブコードで終わった場合は非常に驚きます。


s /条件文/条件式/
Laurence Gonsalves 2011年

1
両方mainを意味するのではなくmain2、まったく同じであるとは思いませんか?
ColinD 2011年

印象的です。今までバイトコードをコンパイルできるとは知りませんでした。
カイル

2
@Kyle:Javaをコンパイルしてから、javapで逆コンパイルしました。
Jon Skeet 2011年

1
@カイル:その通り。私はほとんどバイトコードが同一であると思っていました。現状では、ほぼ同じです:)
Jon Skeet 2011年

10

どちらの例もおそらく同一またはほぼ同一のバイトコードにコンパイルされるため、パフォーマンスに違いはありません。

実行速度に違いがあった場合でも、最も慣用的なバージョンを使用する必要があります(これは、単純な条件と2つの単純な部分式に基づいて単一の変数を割り当てるための2番目のバージョンであり、より複雑な操作を実行するための最初のバージョンです。または、1行に収まらない操作)。


8

これらは同じです。どちらもかなり高速で、通常は約10〜30ナノ秒です。(使用パターンによる)この時間枠はあなたにとって重要ですか?

あなたはあなたが最も明確であると信じていることをするべきです。


4

他のすべての答えに追加するだけです:

2番目の式は、多くの場合、三項/三項演算子/ステートメントと呼ばれます。式を返すので非常に便利です。通常の短いステートメントのコードがより明確になる場合があります。


4
実際のこの良い例:Javaでは、式の結果に基づいてString finalを作成する必要がある場合、3値構文final String whichTable =(Integer.parseInt(clientId)> 500)を使用できますか?"serverClients": "offlineClients"; 次に、whichTableがfinalである必要がある場所で式の値を使用できます。以下は違法です。finalStringwhichTable= ""; if(Integer.parseInt(clientId)> 500){whichTable = "serverClients"; } else {whichTable = "offlineClients"; }
James Perih 2013

@JamesPerihfinalフィールドの場合、コンストラクターブロックを使用して値を設定でき(条件演算子は10億倍優れたIMOに見えますが)、ローカル変数を使用すると、後でコードブロックで最初に使用する前に値を割り当てることができます。三元が有利になる唯一のケースは、コンストラクターをif-else呼び出すとき、super(...)またはthis(...)コンストラクター内にあるときだと思います。
Kröw


0

三項演算子は、if-else条件よりも高速です。

public class TerinaryTest {
    public static void main(String[] args)
    {
        int j = 2,i = 0;
        Date d1 = new Date();
        for(long l=1;l<100000000;l++)
            if(i==1) j=1;
                else j=0;
        Date d2 = new Date();
        for(long l=1;l<100000000;l++)
            j=i==1?1:0;
        Date d3 = new Date();
        System.out.println("Time for if-else: " + (d2.getTime()-d1.getTime()));
        System.out.println("Time for ternary: " + (d3.getTime()-d2.getTime()));
    }
}

試験結果:

トレイル-1:

if-elseの時間:63

三項の時間:31

トレイル-2:

if-elseの時間:78

三項の時間:47

トレイル3:

if-elseの時間:94

三項の時間:31

トレイル-4:

if-elseの時間:78

三項の時間:47


あなたの例を実行したとき、私は正反対の結果を出しました。これは、結果が信頼できないことを示しています。残念ながら、あなたはマイクロベンチマークの罠に陥っています-マイクロベンチマークを正しく行うのは非常に難しいことで有名です。いくつかの例については、ここで見ることができます:stackoverflow.com/questions/2842695/what-is-microbenchmarking
Rogach

あなたの特定の例は少なくともこれらの問題に苦しんでいます:4回の試行では十分ではありません、常に同じ順序でテストを実行します(最初のif-else、2番目の三項)、テストを実行する前にJVMをウォームアップしませんなど。
rogach
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.