3

重複の可能性:
Java:If vs. Switch

プログラミングで観察されるすべての条件ステートメントについて、これらのブロックのどれが最も好ましいか:

  1. 三項演算子
  2. else-ブロックの場合
  3. スイッチブロック

前もって感謝します!

4

6 に答える 6

5

もちろん、さまざまな方法で比較を実装できます。

私はそれをこのようにしました:

共通ブロック:

int a = 42;
int k = 17;

もしも:

if (a == 42) 
    k+=4;
else    k+=5;

場合:

switch (a) {
    case 42: k+=4; break;
    default: k+=5; break;
}

三元:

k += (a == 42) ? 4 : 5; 

それらは同じバイトコードにコンパイルされません:

l *Tern*.class
-rw-r--r-- 1 stefan stefan 704 2012-04-27 14:26 CaseIfTern.class
-rw-r--r-- 1 stefan stefan 691 2012-04-27 14:26 IfTernCase.class
-rw-r--r-- 1 stefan stefan 728 2012-04-27 14:26 TernIfCase.class

ただし、2つだけではなく、複数のケースがある場合は、スイッチの利点が役立ちます。

と三元が2つ以上のケースでカスケードする場合。

しかし、それらは慣用的に/意味的に異なります。三項演算子は何かを返しますが、ifまたはスイッチは返しません。

したがって、何を比較する必要があるかはそれほど明確ではありません。

しかし、私は次の結果でベンチマークを作成しました。

0   if      tern    case 
1   3.103   0.244   0.118   
2   0.306   0.276   0.309   
3   0.382   0.329   0.328   
4   0.464   0.435   0.458   
5   5.045   1.519   1.248   
6   4.57    3.088   2.915   
7   4.036   2.977   3.015   
8   3.197   3.834   3.893   
9   4.631   4.523   5.488   
10  6.445   3.891   3.09    

ベンチマークプロット(ベンチマークプロット)

これは、それらが実際には大きな違いをもたらさないこと、およびキャッシュ効果が、VMを加熱した後でも、5Mの場合に影響を与えることを示しています。

実際の状況では、ほとんど何も起こらない100万回の呼び出しはめったにありません。しかし、何かが起こった場合、if / case/ternaryの時間はすぐに無関係になります。

これが私がテストしたコードです:

public class CaseTernIf
{
    public static int aORbIf (int a) {
        if (a == 2) 
            return 4;
        else    return 5;
    }

    public static int aORbTern (int a) {
        return  (a == 2) ? 4 : 5;
    }

    public static int aORbCase (int a) {
        switch (a) {
            case 2:  return 4;
            default: return 5; 
        }
    }
}

テストコード(Scala)は次のとおりです。

object IfCaseTernBench extends Benchcoat [List[Int], Seq[Int]] {

  type I=List[Int]
  type O=Seq[Int]
  val name = "CaseTern"
  /** We return a List of random Ints numbers here. */
  def iGenerator (n: Int) : I = (for (x <- 1 to n) yield math.abs (random.nextInt (3))).toList
  def takePart (li: I, n: Int) : I = li.take (n) 

  /* Each algorithm is called by a mapping to a static method.  */
  def ifTest   (i: I) : O = i.map (CaseTernIf.aORbIf) 
  def caseTest (i: I) : O = i.map (CaseTernIf.aORbCase) 
  def ternTest (i: I) : O = i.map (CaseTernIf.aORbTern) 

  // Map of Test names -> methods to test
  val list2bench: List [(String, I => O)] = List (
       "if test"    -> ifTest _
     , "case test"  -> caseTest _
     , "tern test"  -> ternTest _
  )

  def test = { 
     list2bench.foreach (algo => println (algo._2))
  }
}

更新しました:

そしてここにBenchCoatのソースがあります

于 2012-04-27T12:34:48.577 に答える
1

三項演算子は、else-ifブロックが必要とするアセンブリで「goto」を必要としないという理由だけで最も効率的です。スイッチケースは、else-ifブロックよりも効率的ではないと思います。else-ifブロックで1つの値を比較している場合(基本的に、すべてのスイッチが最終的に実行しているため)。

ただし、別の考慮事項、つまり明快さを考慮に入れる必要があります。最も効率的な使用法を選択するためのより重要なことは、明確で簡潔なコードを書くことです。このためには、三項演算子ではなく、else-ifまたはswitchブロックをお勧めします。そうしないと返される値を探して目を交差させ始めるからです。

于 2012-04-27T10:52:06.677 に答える
1

最新のコンパイラを使用している場合、大きな違いはありません。コンパイラがコードを最適化した後、ネイティブコードはほぼ同じになるはずです。

于 2012-04-27T10:52:37.887 に答える
0

三項演算子は、if(something){yay} else {boo}を書くための省略形であり、より簡単な割り当てが実行されます。三項演算子はifelse構文に展開され、バイトコードに違いはありません。

于 2012-04-27T10:53:14.377 に答える
0

私は次のテストを行いました:

public class IfElseSwichTernary {

    public static int aORbIf(int a) {
        int x = 0;

        if (a == 2) {
            x = 4;
        } else if (a == 3) {
            x = 5;
        } else if (a == 4) {
            x = 6;
        } else {
            x = 7;
        }           
        return x;
    }

    public static int aORbTern(int a) {
        int x = 0;

        x = (a == 2) ? 4 : ((a == 3) ? 5 : ((a == 4) ? 6 : 7));         
        return x;
    }

    public static int aORbCase(int a) {
        int x = 0;

        switch (a) {
        case 2:
            x = 4;
            break;
        case 3:
            x = 5;
            break;
        case 4:
            x = 6;
            break;
        default:
            x = 7;
        }           
        return x;
    }
}

そして、Javaデコンパイラーを使用して逆コンパイルし、次のコードを取得しました。

パブリッククラスIfElseSwichTernary{

public static int aORbIf(int a) {
    int x = 0;

    if (a == 2) {
        x = 4;
    } else if (a == 3) {
        x = 5;
    } else if (a == 4) {
        x = 6;
    } else {
        x = 7;
    }           
    return x;
}

public static int aORbTern(int a) {
    int x = 0;

    x = (a == 2) ? 4 : ((a == 3) ? 5 : ((a == 4) ? 6 : 7));         
    return x;
}

public static int aORbCase(int a) {
    int x = 0;

    switch (a) {
    case 2:
        x = 4;
        break;
    case 3:
        x = 5;
        break;
    case 4:
        x = 6;
        break;
    default:
        x = 7;
    }           
    return x;
}

}

これは、コンパイラが何も変更しないことを意味します(JVMを変換して命令を実行するときにJVMが変更されるかどうかはわかりません)

それが同じ論理で言うなら、私たちが3つ以上の条件を話しているとき、スイッチはパフォーマンスにもっと影響します。

于 2012-04-27T14:13:03.803 に答える
0

これは、JVMの実装とバージョンによって異なりますが、ステートメントが最速であるかどうかは一般的には言えません

たとえば、生成されるバイトコードもすべてのステートメントで同じである可能性があります。

于 2012-04-27T23:35:41.753 に答える