web-dev-qa-db-ja.com

switchステートメントは、一連のifステートメントよりも優れていますか?

重複の可能性:
switchステートメントを使用する必要がありますか?それ以外の場合は長く使用しますか?

私は挿入ソートを実行する小さなプログラムに取り組んでいます。数字はキーボードから入力され、「num」という変数に格納されます。入力した数値を取得するために、switchステートメントを使用することにしました。

switch( e.getKeyCode() ) {

    case KeyEvent.VK_0: num = 0; break;
    case KeyEvent.VK_1: num = 1; break;
    case KeyEvent.VK_2: num = 2; break;
    case KeyEvent.VK_3: num = 3; break;
    case KeyEvent.VK_4: num = 4; break;
    case KeyEvent.VK_5: num = 5; break;
    case KeyEvent.VK_6: num = 6; break;
    case KeyEvent.VK_7: num = 7; break;
    case KeyEvent.VK_8: num = 8; break;
    case KeyEvent.VK_9: num = 9; break;
}

もう1つの行動方針は、一連のifステートメントを使用することだったかもしれないことに気付きました。

if( e.getKeyCode() == KeyEvent.VK_0 )
    num = 0;
else if( e.getKeyCode() == KeyEvent.VK_1 )
    num = 1;
etc. for every number up until 9.

次に、switchステートメントと一連のifステートメントの本質的な違いは何かと思いました。書くスペースと時間を節約できることは知っていますが、それほど多くはありません。だから、私の質問は、スペースを除いて、switchステートメントは一連のifステートメントとは何らかの点で異なりますか?より速く、エラーが発生しにくくなりますか?

この質問は本当に私のコードにそれほど影響を与えません。ただ疑問に思っていました。また、この質問は、他のプログラミング言語ではなく、Java言語に関係します。

16
kullalok

機能的には同じだというのは正しいことです。しかし実際には、switchステートメントが非常に簡潔であるのに、なぜすべてを入力(またはカットアンドペースト)するのでしょうか。

違いは機能性ではなく、意図の違いです。 switchステートメントを作成すると、コードのこのセクションが1つの単一変数の状態に基づいて複数の方法に分岐する可能性があることを読者に実質的に伝えます。このステートメントはコンパイラーによって強制されます。

ただし、ifブロックを記述するときは、1つの変数のみが関係していると意図的に述べているわけではありません。一連のifsを作成する場合、提案どおり、分岐が単一の変数のみに基づいていることを確認するのははるかに困難です。これはメンテナンスの問題です。将来的にコードを変更する必要がある開発者は、その決定に焦点を絞ることを意図していたことに気付かず、その変数を使用しない条件を追加し始める可能性があります。誰かがやって来て、「最後のキーシーケンスが5-4-8だったらnumを10にしたい」と言って、ブロックの最後に追加のelse ifを付けます。最終的にそのセクションは、誰も理解できないif...else if条件のグルディアンノットになります。将来はあなたを憎み、悪いカルマがあなたのアカウントに追加されます。

可能な場合はswitchステートメントを使用してください。このコードのセクションは単一の変数に依存しており、将来性がはるかに高いことを明確に伝えています。

22
Michael K

switchの能力は2つあります。

  1. より説明的です
  2. CPUサイクルを節約する

あなたの投稿はすでにswitchsのチェーンと比較してifの説明性についてコメントしているので、パート2に集中します。

スイッチラベルの数がNの場合、ifsのチェーンはディスパッチするのにO(N)かかりますが、switchは常にO(1)でディスパッチします。これがその方法です。コンパイラはスイッチラベルのアドレスを配列に配置し、ラベル値に基づいてインデックスを計算し、スイッチ式を値と1つずつ比較せずに直接ジャンプを実行します。文字列がスイッチラベルとして使用されている場合、コンパイラはハッシュテーブルを作成し、O(1)でもアドレスを検索します。

スイッチの数が多くなると(100を超える)、switchifsのチェーン間の変換をマイクロ最適化と見なすことができなくなります。特に、タイトなループ。プロファイラーからifsのチェーンにかなりの時間がかかっていると通知された場合は、switchとして書き換えることで解決できる場合があります。

11
dasblinkenlight

一部の人々は、if-elseよりもスイッチの方が読みやすいと感じています。しかし、パフォーマンスを心配することはミクロ最適化の領域にあるという信念に同意します。

SO JavaこのQのバージョン
SO JavaこのQ v2のバージョン
このQのSO C++バージョン
このQ v2のSO C++バージョン
SO C#バージョン...

2
user53019

switchは、一連のif/else ifステートメントよりも効率的です。 Cの例については この記事 を参照してください。大きな違いは、ifステートメントの場合、各ケースの条件は何でもかまいません。たとえば、次のコードと同等のコードを記述できます。

If it's raining, put on a jacket, otherwise if it's a Sunday, call your mother.

ただし、switchを使用すると、各比較は等価性のテストになります。変更されるのは、比較する値だけです。リンクで説明されているように、ケースの値がすべて互いに近い場合、コンパイラはジャンプテーブルを使用してスイッチを実装できます。つまり、コンパイラーは、オンに切り替えている値を使用して、その場合のコードのアドレスを直接計算できます。これにより、一連の比較の必要がなくなります。さて、本当に賢いコンパイラーは、一連のifステートメントを同じ方法で使用しており、同じことを実行していることに気付くでしょう。それが一般的な最適化であるかどうかはわかりません。

そうは言っても、コンパイラーが生成するコードについてはあまり心配しません。代わりに、ifswitchのどちらかを、あなたや他のプログラマにとって自然に見えるものに従って選択してください。 switchは、各ケースに対応する値があるいくつかのケースから1つのケースの選択を表します。それはデマルチプレクサです。比較している値を除いて、すべて同じ条件のifステートメントのシーケンスがあることがわかった場合、switchはより適切で、短く、より明確です。それを表現する方法。

2
Caleb