スイッチケースの使用中にデフォルトのケースを追加する必要がありますか?


41

最近のコードレビュー中に、ブロック内で何もすることがなくても、ブロックが使用されるdefaultすべてのファイルにケースを入れるように頼まれswitchましたdefault。つまり、defaultケースを入れて、何も書いてはいけないということです。

これは正しいことですか?それはどのような目的に役立つでしょうか?


9
それはあなた次第です...私はスーパーバイザーのコードスタイルを意味します。
SD

1
デフォルトのケースが必要ない場合もあると思います。列挙型の切り替えを検討してください。スイッチは、すべての可能な値のケースを定義します。今列挙に値を追加する必要があり、そのスイッチの場合を加えることにつながります。そうしなかった場合、この新しい列挙値に対して何かを実行したいが、コードはしないため、これはエラーになる可能性があります。あなたのコンパイラは、それについてあなたに警告することができます(私はJavaについては確信していません)が、デフォルトのケースを入れなかった場合のみです。または、コードが絶対に到達しないことが確実な場合、デフォルトのケースで警告を出力できます。
リーム

6
私と私の友人はこれを「開発者例外」ケースと呼んでいます- 論理的/コード上の理由により、コード内の何かが発生してはならないことがわかった場合、スローされる「開発者例外」を追加します。そうすれば、これが発生した場合、開発者例外がスローされ、少なくともどこで深刻な問題が発生したかがわかります。
マルコ

回答:


31

defaultステートメントが不要な場合は、次の3つのケースがあるようです。

  1. を入力する値のセットは限られているため、他のケースは残っていませんswitch case。しかし、これは時間とともに(意図的または偶然に)変更される可能性がありdefault case、何か変更があった場合は、_間違った値についてユーザーにログを記録するか、警告することができます。

  2. がどのように、どこswitch caseで使用され、どの値が入力されるかを知っています。繰り返しますが、これは変更される可能性があり、追加の処理が必要になる場合があります。

  3. その他の場合は、特別な処理は必要ありません。これが当てはまる場合、default case受け入れられるコーディングスタイルであり、コードを読みやすくするため、を追加するように求められていると思います。

最初の2つのケースは仮定に基づいています。そのため(定期的なコードレビューがあるため、それほど小さくないチームで作業していると仮定すると)、これらの仮定を立てる余裕はありません。誰があなたのコードで作業するのか、あなたのコードで関数/呼び出しメソッドを呼び出すのかわかりません。同様に、他の人のコードで作業する必要があるかもしれません。同じコーディングスタイルを使用すると、誰か(自分のコードを含む)のコードを簡単に処理できます。


14
ケース1および2では、デフォルトのケースはエラーです。コーディングスタイルが常にデフォルトを使用する場合は、それを実行しますが、1および2でエラーを出力します。可能であれば、コンパイル時に出力する必要がありますが、Javaの場合は常に可能とは限りません。少なくとも、ユーザーは「この値を渡すことで自分自身を撃っている」というメッセージを受け取ることが重要だと思います
-martiert

11
デフォルトケースは常に良いアイデアです。たとえば、列挙型の場合、誰かが列挙型に新しいエントリを追加すると、デフォルトケースはthrow new IllegalStateException("Unrecognised case "+myEnum)エラーの場所と内容を示すのと同様の処理を行う必要があるためです。
リッチ

これは、発生してはならないことがわかっていelseif/else ifも、毎回必ず句が必要であることを意味しますか?私には良い考えのように思われない
...-jadkik94

2
私の作品から逸話を追加する場合:enumを使用していくつかのクラスをインスタンス化するファクトリメソッドがありました。そのプロジェクトに新しいクラスを追加するたびに、値を列挙型とスイッチのケースに追加する必要があるという指示を残しました。もちろん、コードを閉じてから1週間後には動作しなくなりますが、例外を発生させることはできません。プログラマーのところに行って、「スイッチにケースを追加しましたか?」と尋ねました。そして確かに、彼はしませんでした。その日、私は例外を変更して、「このメッセージを受け取ったら、コードに触れた最後の開発者を責めなさい」と言った。
-Ziv

28

これは正しいことですか?それはどんな目的に役立つでしょうか?

会社のコーディング標準では、すべてのswitchステートメントにデフォルトのケースを要求することは珍しくありません。それの1つの理由は、それが読者が終わりを見つけるのを簡単にするということですswitch。別の、おそらくより良い理由は、条件が期待と一致しない場合にコードが何をすべきかを少し考えさせることです。要件の理由に関係なく、それが会社の標準である場合、そうでない気密の理由がない限り、それに従う必要があります。

switch可能性のあるすべての条件にケースが含まれていると思われる場合assertは、デフォルトのケースにステートメントを入れることをお勧めします。そうすれば、誰かがコードを変更し、あなたswitchがカバーしていない条件をうっかり追加した場合、彼らはヒットしassert、コードのその部分に対処する必要があることに気付くでしょう。

あなたがいる場合switchにのみ可能な条件のいくつかをカバーしていますが、何も特別なが他人のために行う必要があり、あなたは空のデフォルトのケースを残すことができます。そのケースにコメントを追加して、デフォルトのケースが意図的に空であることを示すことをお勧めします。これは、ヒットした条件で作業を行う必要がないためです。


1
assertですか?
フライ

1
@FLYこれはJavaのキーワードであり、通常はC、C ++などのマクロです。どちらの場合も、assertを使用して、仮定が真のままで例外をスローするか、そうでない場合はエラーを引き起こすかをテストします。
カレブ

私は、ウィキペディアへのリンクと私の以前のコメントを編集した
FLY

空のケースを残さないでください。スイッチが考えられるすべての条件をカバーしていない場合は、2番目の段落のデフォルトケースにアサートを追加することを提案したのと同じ理由で、デフォルトケースの他の条件をアサートする必要があります。
rold2007

12

純粋な列挙型を「切り替える」場合、デフォルトのフォールバックを持つことは危険です。後で列挙型に値を追加すると、コンパイラは、カバーされていない新しい値でスイッチを強調表示します。そこにデフォルト句がある場合、コンパイラは沈黙を保ち、見逃す可能性があります。


1
実行時ではなくコンパイル時で問題をキャッチした場合、+ 1。
SylvainD

どのように完全に誤解を招く答えが投票され、受け入れられるのだろうか。クイックグーグルでは、Javaコンパイラにこの種の警告があることが示されています。なぜ、実行時にエラーを待つのでしょうか?
アルトゥール

この振る舞いについては知りませんでした。私のideoneコードサンプルideone.com/WvytWqは、そうでないことを示唆しています。あなたが真実だと仮定すると、誰かが列挙型に値を追加しても、コードを再コンパイルしないとどうなりますか?
エモリー


1
明らかに、デフォルト値がないと、新しい値はswitchステートメントによって処理されません。しかし、インターフェイスが変更されたときに実装を再コンパイルしないと、ビルドシステムが本当に壊れます。
アルトゥール

9

多くの点で、この質問はよく聞かれる質問と同じです。すべてのオプションをカバーする/ ラダーの最後に句が必要elseifelse ifですか。

答えは、構文的に言えば、そうではありません。しかし、そこには...

default句は、(少なくとも)二つの理由が存在し得ます。

  1. エラーハンドラとして-確かに、ここに到達しないでください!できる主張はありますが、もしそうなら? データ破損、さらに悪いことに、適切にトラップされない場合、データ検証はプログラム障害のルートになりません。この場合、空の句であってはなりません!
  2. 設計/コードカバレッジ-フローチャートの最も単純な形式でも、ifステートメントからのルートと、常にotherwiseケースからのルートが2つあります。これらをソースコードに含めない理由は何もありません。

私の哲学は常に非常にシンプルです。2つのオプションの最悪のシナリオを評価し、最も安全な方法を選びます。空のelseor default句の場合、最悪の場合のオプションは次のとおりです。

  • それらを含める:追加の3行または4行の「冗長」コード。
  • それらを含めない:不正なデータまたは予期しない状態がトラップされないため、プログラムが失敗する可能性があります。

ドラマチック?たぶん...しかし、私のソフトウェアは、それがうまくいかない場合、人々を殺す可能性があります。むしろそのリスクを冒したくない。


余談として、MISRA-Cガイドラインは {所属のプロファイルを参照}をお勧めしますdefaultすべてのための句switch


はしごの終わりだけではありません。質問です:私は必要なのですelseif。しかし、あなたが言ったように、いいえ、そうではありません。
-ott--

エラーハンドラとして、空のデフォルトを回避するわずかに変更されたフォームを提案します。人々を殺すことに関しては、私はそれが実際に重要ではないと思います-あなたはデフォルト条項があるかどうかにかかわらず人々は同じように死んでしまいますが、それは彼らが死んだ理由を理解しやすくします。
エモリー

良い点、@ emory-それはあまり明確ではありませんでした...編集されました:)
アンドリュー

6

Javaは「デフォルト」の文を持っているあなたを強制するものではありませんが、ある良い練習コードは(今のところ)に到達することはないかもしれ場合でも、1時間のすべてを持っています。いくつかの理由があります:

到達不能なデフォルトの句を使用することで、コードの読者に値を検討したことを示し、何をしているかを知ることができます。また、たとえば、新しい列挙値が追加され、スイッチが新しい値を黙って無視してはならないなど、将来の変更も許可します。代わりに例外をスローするか、何か他のことを行うことができます。

渡される予期しない値(enumをオンにしない場合)をキャッチするには、たとえば、予想よりも大きい場合も小さい場合もあります。

「デフォルト」アクションを処理するために-スイッチは特別な動作用です。たとえば、変数はスイッチの外部で宣言されていても、初期化されておらず、各ケースで異なる値に初期化されている場合があります。この場合のデフォルトは、スイッチの直後のコードがエラー/例外をスローしないように、デフォルト値に初期化できます。

デフォルトに何も設定しない(例外、ロギングなどを設定しない)場合でも、デフォルトが発生しないと考えたというコメントでさえ、コードを読みやすくすることができます。しかし、それは個人的な好みに帰着します。


2

また、使用している言語の哲学に依存することも付け加えます。たとえば、「クラッシュさせる」ための一般的なアプローチであるErlangでは、デフォルトのケースを定義せcaseず、対処されていない状況が発生した場合にステートメントでエラーを発生させます。


0

すべてのケースを証明可能で永続的にカバーしていない限り、常にデフォルトを使用する必要があります。費用はかかりません。また、進化するプログラムで切り替えステートメントを維持できない場合の保険です。

本当に他のケースを気にしないと確信している場合、デフォルトはbreak; // do n't careですが、デフォルトはdefaultのようなものでなければなりません:throw new Error( "unexpected value");

同様に、ドロップスルーする効果にコメントを追加せずに、重要なケースの構造を「ドロップスルー」しないでください。Javaは設計段階でこれを間違っていました。


-2

検討する

enum Gender
{
       MALE ,
       FEMALE ;
}

そして

void run ( Gender g )
{
      switch ( g )
      {
           case MALE :
                 // code related to males
                 break ;
           default :
                 assert Gender . FEMALE . equals ( g ) ;
                 // code related to females
                 break ;
      }
}

これは、MALEケース、FEMALEケース、および例外をスローするデフォルトのケースよりも優れていると主張します。

テスト段階で、コンピューターはgがFEMALEかどうかを確認します。生産中、チェックは省略されます。(ええ、微小最適化!)

さらに重要なことは、100%のコードカバレッジという目標を維持することです。例外をスローするデフォルトのケースを作成した場合、どのようにテストしますか?


1
1.最適化の必要はありません-過去30年ほどコンパイラーでデッドコード除去が使用されており、JITによって除去されます。2.通常、100%のコードカバレッジは重要とは見なされません(一方で、100%のカバレッジはすべてのエッジケースをキャッチするとは限らず、別のテストでは正しいプログラムのassert_not_reached行をキャッチしません)。この場合、デフォルトのケースを残さないと、コンパイラエラーが発生します。一方、アサートが機能するかどうかをどのように確認しますか(同じ行を「発生しない、約束します」ではなく、問題をシフトして100%のカバレッジで非表示にします)。
マチェイピエチョトカ

1
3.いつGender . FEMALE . equals ( FEMALE ) ;評価されfalseますか?あなたは意味しましたGender.FEMALE.equals (g)が、安定している列挙型への参照に依存することができるので、あなたはただ書くことができますg == Gender.FEMALE。4.(個人的な意見)そのようなコードは読むのがはるかに難しく、少し紛らわしいエラーを生成します。
マチェイピエチョトカ

@MaciejPiechotkaはgについてよくキャッチします。はい、マイクロ最適化は利点ではありませんが、欠点でもありません。100%のコードカバレッジは、それがあなたの目標の1つであり、コードカバレッジツールがアサートをチェックしない場合(そうするべきではない場合)には有益です。
エモリー

では、なぜそれが私の目標の1つになるのでしょうか?「興味深い」部分は、すべてのエッジケースでテストする必要があり(コード行にマッピングするかどうかに関係なく)、「退屈な」部分はテストの時間を節約するために単純にスキップできます。私見コードカバレッジはテストの悪いメトリックです。
マチェイピエチョトカ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.