【連載11】Javaプログラミングの基本 選択(switch文)

条件の分岐はif文以外に、switch文という制御構文を使っても実現できます。

単純な比較条件が多くなるような場合、if文よりもこちらのswitch文を使用した方が見やすくスッキリしたソースコードになります。

今回の記事では、switch文の使い方についてif文との違いや使い分けについて考えながら見ていきます。

switch文の使い方

switch文は値によって処理を分岐させるという特徴があります。

式を評価した値に応じて、どの分岐処理を実行するかが決まります。

switch文の構文は以下のとおりです。

switch ( 式 ){
  case 値1:
    // 式を評価した値が値1と一致した場合に実行される処理
    ...
    break;
  case 値2:
    // 式を評価した値が値2と一致した場合に実行される処理
    ...
    break;
  ...
}

switch文ではまずはじめに式を評価します。

※式では整数型( char, byte, short, int )、Stirng型もしくは列挙型を戻す式とする必要があります。

caseには値を記述し、switchの式が戻す値に応じて、処理が分岐します。(「case 値」の後に記す記号はコロン(:)である点に注意してください。)

ややこしい説明となってしまいましたが、一度以下のサンプルコードを見てください。

public class Sample11_01{
    public static void main(String[] args){
        int num = 1;

        switch(num){
            case 1:
                System.out.println("値は1です。");
                break;
            case 2:
                System.out.println("値は2です。");
                break;
            case 3:
                System.out.println("値は3です。");
        }
    }
}
値は1です。

caseの後に記述する値は定数になります。その定数のことををラベルと呼びます。

式によって評価された値、つまり上記サンプルの場合は変数numの値と定数(ラベル)と比較して、値が一致すれば、そのラベルの位置へ処理が飛びます。

switch文の処理の流れとbreak文の関係

switch文をif文の同じ感覚で見てしまうと、caseごとにブロックが別れ、該当したブロック内の処理のみが実行されるように思えてしまいます。

switch文のcaseがif文のelse ifに対応し、else ifブロックごとに別れ、該当したブロック内の処理のみが実行される。

そんな風に考えてしまいがちですが、それは誤りです。

文章で書くとややこしくなるので、まずは以下のサンプルコードを見てください。

public class Sample11_02{
    public static void main(String[] args){
        int num = 1;

        switch(num){
            case 1:
                System.out.println("値は1です。");

            case 2:
                System.out.println("値は2です。");

            case 3:
                System.out.println("値は3です。");
        }
    }
}
値は1です。
値は2です。
値は3です。

ほぼ前述のサンプルコードと同じですが、一部違いがあります。その違いに気が付くでしょうか。

答えはbreak文がありません。

そしてそれにより、実行結果が意図しない結果になってしまっています。

switch文は「処理を分岐させることができる」と書きましたが、より正確に説明すると「式によって評価された値に応じたラベルの位置に処理を移す」となります。

break文との関係を含め下図を見てください。

上図のとおり、式の評価結果に一致したラベルに処理を移し、そこから後続の処理をすべて実行することになります。

もし、ラベル内の処理だけを実行したいのであれば、break文により、switch文を明示的に終了させる必要があります。なお、最後のラベル(上図ではラベル3)にはbreak文は必要ありません。それ以降の処理がないためです。

ちなみにswitch文の応用的な使い方として、以下のように複数のラベルに対して同じ処理を実行させることもできます。

public class Sample11_03{
  public static void main(String[] args) {
      int num = 4;

      switch(num){
          case 1:
          case 2:
          case 3:
              System.out.println("値は1、2、3いずれかです。");
              break;
          case 4:
          case 5:
              System.out.println("値は4、5いずれかです。");
      }
  }
}
値は4、5いずれかです。

上記サンプルでは、変数numの値が1、2、3のいずれかであれば、「値は1、2、3いずれかです。」という文字列を出力し、3、4であれば「値は4、5いずれかです。」と出力します。

このように複数のラベルを続けて記述することで複数の値と一致した場合に行う処理を定義することができます。

defaultラベルを用いたswitch文

いずれの値(ラベル)とも一致しなかった場合に実行したい処理がある場合はdefaultラベルを使います。

switch ( 式 ){
  case 値1:
    // 式を評価した値が値1と一致した場合に実行される処理
    ...
    break;
  case 値2:
    // 式を評価した値が値2と一致した場合に実行される処理
    ...
    break;
  default:
    // いずれの値とも一致しなかった場合に実行される処理
  ...
}

defaultラベルはif文の「それら以外」を意味するelseに相当します。

if文との違い

switch文とif文の違いはどこにあるのでしょうか。それがわかることで使い分けの基準も見えてきます。

その違いですが、if文は比較演算子や論理演算子を使って、複数の変数どうしを比較することができましたが、switch文はそうしたことが基本的にはできません。

if文はある意味、万能型であり、switch文でできることはif文でも全て出来ます。例えば以下サンプルのようなコードはどちらで記述しても同じ結果となります。

switch (n) {
    case 2:
        ...
        break;
    case 5:
        ...
        break;
    default:
        ...
}
if ( n == 2 ) {
    ...
}else if ( n == 5 ) {
    ...
}else {
    ...
}

このサンプルを見比べたとき、変数の値が何かの定数と一致しているかどうかを判定したいとき、switch文の方がその意図が読み解けやすくなっていると思いませんでしょうか。

値が2のときに実行する処理、値が5のときはに実行する処理、それ以外の処理といった分岐を作りたい場合、switch文の方がソースコードの可読性を上げるという意味で適していると言えます。

一方で、ANDやORなどの論理演算子を使った複雑な条件式をswitch文では基本的には作ることはできないので、そうしたときはif文を使います。

まとめ

今回はswitch文に見てきました。if文と同じく処理を分岐させたい場合に使うものですが、if文とは異なる特徴があります。

基本的にswitch文では複雑な条件による分岐を行うことはできず、決まった値(定数)によって処理を分岐させたい場合に使われます。

そのような分岐の場合、switch文の方がソースコードの可読性が上がり、保守性の面でif文より優れていると言えます。

一方で、if文でできることがswitch文ではできないことがあります。

if文では値の大小比較や論理演算子を用いて複数の条件を組み合わせた条件式を作ることができますが、switch文ではそうしたことは基本的にはできません。

それら特徴を捉え、両者を使い分けることができれば、より良いソースコードを書けるようになるでしょう。