1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Java が提供する制御文をまとめました

Last updated at Posted at 2024-11-06

はじめに

現在、私が進行しているJavaの勉強会でまとめた内容です。

内容に不正確な点があれば、ご指摘いただけるとありがたいです。

韓国人として、日本語とコンピュータの勉強を同時に行うために、ここに文章を書いています
翻訳ツールの助けを借りて書いた文章なので、誤りがあるかもしれません

制御文

ソースファイル内の文は、通常、上から下に向かって記述された順に実行されます。しかし、制御フロー文を使用すると、実行の流れを分岐させたり、条件に応じて特定のコードブロックを実行したりすることができます。

  1. 条件文 (Decision-Making Statements)

    • if
    • if-else
    • switch
  2. 繰り返し文 (Looping Statements)

    • for
    • while
    • do-while
  3. 分岐文 (Branching Statements)

    • break
    • continue
    • return

制御文
コードの流れを制御する文法

意思決定文 (Decision-Making Statements)

if

  • 条件式が真である場合、コードを実行します
if (条件式) {
    // 条件式が真のときに実行されるコード
}

if-else

  • 条件式が真であれば if、偽であれば else を実行します
if (条件式) {
    // 条件式が真のときに実行されるコード
} else {
    // 条件式が偽のときに実行されるコード
}

else-if

  • 条件式を順次評価し、真のときに該当するコードを実行します
if (条件式1) {
    // 条件式1が真のときに実行されるコード
} else if (条件式2) {
    // 条件式2が真のときに実行されるコード
} else {
    // 上記のすべての条件が偽の場合に実行されるコード
}

switch / case

  • 変数の値に応じて複数のケース (case) の中から1つを選択します
  • case の値が一致する場合にそのコードを実行します
switch (変数) {
    case 値1:
        // 変数の値が値1のときに実行されるコード
        break;
    case 値2:
        // 変数の値が値2のときに実行されるコード
        break;
    default:
        // 上記のすべての case に該当しないときに実行されるコード
}

switchとifの速度比較

image.png

次のようにクラスファイルを作成し、コンパイルされたバイトコードを確認しました。

image.png

次のように記述されています。

ここで重要な部分は、

25: tableswitch   { // 1 to 12
                     1: 88
                     2: 94
                     3: 100
                     4: 106
                     5: 112
                     6: 118
                     7: 124
                     8: 130
                     9: 136
                    10: 142
                    11: 148
                    12: 154
               default: 160
          }

この部分が重要だと考えています。

通常、switch文はバイトコードで tableswitchlookupswitch に分けられます
(4バイト以内で連続するコードは tableswitch、非順序データは lookupswitch です)。

これらのコードは、特定のインデックスでジャンプテーブルにアクセスし、「ジャンプ」するように定義されています。

このため、O(1) の時間複雑度を持ちます。

一方、このコードを if-else で再定義すると

image.png

次のように if-else 文で再定義し、バイトコードを確認したところ、

image.png

以下のようにすべてのインデックスを線形に検査していることが確認できました。

条件が n 個追加されるごとに処理時間も n 個分増加します。

したがって、if-else 文の時間複雑度は O(n) となります。

  • 詳細な構成については、こちらで tableswitchlookupswitch を検索すると確認できます

  1. バイトコードを確認すると、switch 文はインデックスジャンプを行い、if-else 文は線形探索を行います
  2. これを時間複雑度で比較すると、switch 文は O(1)、if-else 文は O(n) です

以上の理由から、switch 文は if-else 文よりも性能が優れています。

switch 文の fall-through とその防止

  • break を使用しない場合、一致する case 文の比較後、その後のすべての文が順次実行されます

  • これを「fall-through」と呼びます

前述の switch case コードで、10月の場合を除き、すべての break 文を削除してみました。

image.png

作成されたコードのバイトコードを確認すると、

image.png

10月を除き、すべての goto 文が抜けていることが確認できます。

image.png
また、コードで検査してみると、すべてのインデックスを順に通過し、10月の箇所で goto によって "October" が出力されることが確認できます。

これにより、fall-through がなぜ発生するのかがよくわかります。

バイトコードを確認するとわかるように、最後の節では break 文は必要ありません(次のインデックスに直接続くため)が、保守性やコードの一貫性を考慮して break 文を付けることが望ましいです。

fall-through を防ぐために矢印演算子 -> を使用できます。

image.png
次のように -> 演算子を使用すると、break 文を省略できます。

image.png
自動的に goto を挿入してくれることが確認できます。

String monthName = switch (month)
...

そして、次のように switch 文の返り値を直接割り当てることもできます。

image.png

また、-> を使用すると複数のケースをまとめて宣言することが可能です。

image.png

バイトコードを見ると、すべてがインデックス 88 を指し、複数のケースをまとめて宣言できる機能がサポートされていることが確認できます。

String result = switch (day) {
    case 1, 2, 3 -> "Weekday";
    case 4, 5 -> "Weekend";
    default -> {
        yield "Invalid day";
    }
};
System.out.println(result);

そして、次のように yield 構文を使用して値を返すこともできます。

switch 文に -> を使うべき理由のまとめ

  1. 自動的に break が挿入され、fall-through を防止できる
  2. 1つの case で複数の値を処理できる
  3. yield を使って複雑な値を返すことができる

繰り返し文

while

  • 条件式が真である間、中括弧内のコードを繰り返します
while (条件式) {
    // 条件式が真のときに繰り返し実行されるコード
}

do while

  • while 文を実行する前に必ず実行するコードを定義できます
do {
    // 条件式が真のときに実行されるコード
} while (条件式);

for

  • 条件式が真である間、中括弧内のコードを繰り返します
for (初期値; 条件; 方向&間隔) {
    // 条件が真のときに繰り返し実行されるコード
}

for-each

  • すべてのオブジェクト要素に1つずつアクセスする際に使用します
for (<> <インスタンス>: <繰り返し可能なオブジェクト>) {
    // 繰り返し可能なオブジェクトの各要素に対して実行されるコード
}

分岐文 (Branching Statements)

break

  • 該当ブロックを即座に終了し、次の実行フローに移動します
for (int i = 0; i < 10; i++) {
    if (i == 5) {
        break; // i が 5 のときにループを終了
    }
    System.out.println(i);
}

return

  • 実行を終了し、呼び出し元に値を返します
public int add(int a, int b) {
    return a + b; // 2つの数の合計を返す
}

continue

  • 現在の繰り返しをスキップし、次の繰り返しを実行します
for (int i = 1; i <= 10; i++) {
    if (i % 2 == 0) {
        continue; // 偶数の場合、以降のコードをスキップして次のループに移動
    }
    System.out.println(i); // 奇数のみ出力
}

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?