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


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

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

https://github.com/whiteship/live-study/issues/4

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


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

1. **条件文 (Decision-Making Statements)**
   - `if`
   - `if-else`
   - `switch`

2. **繰り返し文 (Looping Statements)**
   - `for`
   - `while`
   - `do-while`

3. **分岐文 (Branching Statements)**
   - `break`
   - `continue`
   - `return`

https://docs.oracle.com/javase/tutorial/java/nutsandbolts/flow.html

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

## 意思決定文 (Decision-Making Statements)

### if
- 条件式が真である場合、コードを実行します

```java
if (条件式) {
    // 条件式が真のときに実行されるコード
}
```

### if-else
- 条件式が真であれば if、偽であれば else を実行します

```java
if (条件式) {
    // 条件式が真のときに実行されるコード
} else {
    // 条件式が偽のときに実行されるコード
}
```

### else-if
- 条件式を順次評価し、真のときに該当するコードを実行します

```java
if (条件式1) {
    // 条件式1が真のときに実行されるコード
} else if (条件式2) {
    // 条件式2が真のときに実行されるコード
} else {
    // 上記のすべての条件が偽の場合に実行されるコード
}
```


### switch / case
- 変数の値に応じて複数のケース (case) の中から1つを選択します
- case の値が一致する場合にそのコードを実行します

```java
switch (変数) {
    case 値1:
        // 変数の値が値1のときに実行されるコード
        break;
    case 値2:
        // 変数の値が値2のときに実行されるコード
        break;
    default:
        // 上記のすべての case に該当しないときに実行されるコード
}
```
### switchとifの速度比較

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/ce6b6ef1-3a11-a7dc-5808-b86b70eac7f0.png)

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/926ad252-60c3-2d92-4d2f-a553b0719798.png)

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

ここで重要な部分は、

```java
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文はバイトコードで `tableswitch` と `lookupswitch` に分けられます
（4バイト以内で連続するコードは `tableswitch`、非順序データは `lookupswitch` です）。

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

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

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


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/249db471-4142-a34c-6ad8-d01b93bbb32c.png)

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


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/8dc220a0-e2b3-3697-7699-6975cccb9f60.png)

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

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

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


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

https://docs.oracle.com/javase/specs/jvms/se23/html/jvms-6.html

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](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/30230613-fe14-5997-a1de-a11351619337.png)

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/084c358d-c97d-b2fe-2845-de4ed5de8548.png)

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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/23851967-7c38-2294-de4a-63b58760331f.png)
また、コードで検査してみると、すべてのインデックスを順に通過し、10月の箇所で `goto` によって "October" が出力されることが確認できます。

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

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


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

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/ba4aaecf-a502-1eaf-fc69-be8121dcc6e2.png)
次のように `->` 演算子を使用すると、`break` 文を省略できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/1a2269f7-5b7a-7b50-61d8-ff531aedd9a9.png)
自動的に `goto` を挿入してくれることが確認できます。


```java
String monthName = switch (month)
...
```
そして、次のように switch 文の返り値を直接割り当てることもできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/0a8412fa-7138-226d-914c-033d7172cd83.png)

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


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/d027b544-325b-8841-b271-d2f69cb9c51c.png)

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


```java
String result = switch (day) {
    case 1, 2, 3 -> "Weekday";
    case 4, 5 -> "Weekend";
    default -> {
        yield "Invalid day";
    }
};
System.out.println(result);
```
そして、次のように `yield` 構文を使用して値を返すこともできます。

:::note info
**switch 文に `->` を使うべき理由のまとめ**
1. 自動的に `break` が挿入され、fall-through を防止できる
2. 1つの case で複数の値を処理できる
3. `yield` を使って複雑な値を返すことができる
:::

## 繰り返し文

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

### do while
- while 文を実行する前に必ず実行するコードを定義できます

```java
do {
    // 条件式が真のときに実行されるコード
} while (条件式);
```

### for 
- 条件式が真である間、中括弧内のコードを繰り返します

```java
for (初期値; 条件; 方向&間隔) {
    // 条件が真のときに繰り返し実行されるコード
}
```

### for-each
- すべてのオブジェクト要素に1つずつアクセスする際に使用します

```java
for (<型> <インスタンス>: <繰り返し可能なオブジェクト>) {
    // 繰り返し可能なオブジェクトの各要素に対して実行されるコード
}
```

## 分岐文 (Branching Statements)

### break
- 該当ブロックを即座に終了し、次の実行フローに移動します

```java
for (int i = 0; i < 10; i++) {
    if (i == 5) {
        break; // i が 5 のときにループを終了
    }
    System.out.println(i);
}
```


### return 
- 実行を終了し、呼び出し元に値を返します

```java
public int add(int a, int b) {
    return a + b; // 2つの数の合計を返す
}
```

### continue
-  現在の繰り返しをスキップし、次の繰り返しを実行します

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

```