【Java入門】条件分岐について（if文、if-else文、else if文、三項演算子、switch文）

#目的

Java言語を含めたプログラミングの学習を始めたばかりの方、既学習者の方は復習用に、
今回は**条件分岐**について学ぶために書いています。

[【Java入門目次】](https://qiita.com/morioheisei/items/6c7fc063c26e63d890ac)
・[変数と型](https://qiita.com/morioheisei/items/3d27e82d6cd88068dded)
・[型変換](https://qiita.com/morioheisei/items/28ab5fd69570e01cd317) 
・[変数のスコープ](https://qiita.com/morioheisei/items/c56ab32b68ce92d32206)
・[文字列の操作](https://qiita.com/morioheisei/items/e58adadd8535971b69be)
・[配列の操作](https://qiita.com/morioheisei/items/b6acbb1b0c07b40e7f56)
・[演算子](https://qiita.com/morioheisei/items/63088c61e8234dc1f7f5)
・条件分岐 ←今ここ
・[繰り返し処理](https://qiita.com/morioheisei/items/e686e33b60c6a60e87f0)
・クラスについて（準備中）
・抽象クラス（準備中）
・インターフェース（準備中）
・カプセル化（準備中）
・モジュールについて（準備中）
・[例外処理について](https://qiita.com/morioheisei/items/d25d2b67e7530c1aab9d)
・[ラムダ式について](https://qiita.com/morioheisei/items/2bfcc3d8d8440b00e6a9)
・[Stream APIについて](https://qiita.com/morioheisei/items/3a7be38b4d3ef712ccb2)


#条件分岐とは

ソースコード内である条件が満たされているかによって実行する処理を分けることです。
`もし、〇〇ならばAの処理、△△ならばBの処理をする。`といった感じです。

#if文

条件式をもち、その条件の結果に応じた処理を行う場合に使用します。
条件式の結果は`boolean値(true、false)`で返ってきて、**trueの時にif文内の処理が実行されます。**

```text:構文
if( 条件式 ) { 
  処理
};
```

例えば、**条件式がtrueの場合。**

```java:ifがtrueの例
int num = 10;
if (num < 20) {
  System.out.println("numの値は20未満");
}
System.out.println("if文後の処理");
```

実行結果は以下になります。


```text:
numの値は20未満
if文後の処理
```

条件式を判定、結果はtrueなので、if文ブロック内の処理が実行され、その後、ifブロック外の処理が実行される。という流れになります。


**条件式がfalseの場合。**

```java:ifがfalseの例
int num = 10;
if (num < 5) {
  System.out.println("numの値は5未満");
}
System.out.println("if文後の処理");
```

実行結果は以下になります。


```text:実行結果
if文後の処理
```

条件式がfalseなのでif文ブロック内の処理が実行されず、その後の処理だけ実行されています。


また、if文の中にif文を記述する事も可能です。**ネスト(入れ子)**と言います。
ただ、あまり複数記述すると読みにくくなるので気をつけましょう。

```java:ifのネスト
int num = 10;

if (num > 0) {
  System.out.println("numは正の値");
  if (num % 2 == 0) {
    System.out.println("numは偶数");
  }
}
```



##値の比較時の注意

値が同じであるかを比較するには、`==`と記述します。`=`が1つだけの場合、関係演算子ではなく代入演算子になるので注意しましょう。

以下はコンパイルエラーになります。

```java:無効なコード
int a = 20;
int b = 50;
if (a = b) { // int型のaにbを代入しているだけで、条件式が成り立っていない
  System.out.println("aとbの値は同じ");
}
```

値の比較は以下の様にします。

```java:有効なコード
int a = 50;
int b = 50;
if (a == b) {
  System.out.println("aとbの値は同じ");
}
```

```text:実行結果
aとbの値は同じ
```

条件式の箇所で代入を行ってもコンパイルエラーにはならないパターンもあります。

```java:条件式で代入の例
boolean bool1 = false;
boolean bool2 = true;
if(bool1 = bool2) { // 代入の結果、boolean値が返ってくるので条件式として問題ない
  System.out.println("bool1: " + bool1);
  System.out.println("bool2: " + bool2);
}
```

falseのbool1にtrueのbool2を代入した結果、条件式がtrueになります。
よって、if文ブロック内の処理が実行されます。

```text:実行結果
bool1: true
bool2: true
```


#if-else文

条件式がtrueの時だけではなく、falseの時に行いたい処理を記述し、実行する事もできます。

```text:構文
if( 条件式 ) { 
  処理1
} else {
  処理2
};
```

処理1は条件式がtrueの時に実行され、処理2は条件式がfalseの時に実行されます。

例えば、**条件式がtrueの場合。**

```java:ifがtrueの例
String name1 = "柳田";
String name2 = "柳田";
if (name1 == name2) {
  System.out.println("name1とname2は同じ");
} else {
  System.out.println("name1とname2は同じではない");
}
System.out.println("if-else文後の処理");
```

実行結果は以下になります。


```text:実行結果
name1とname2は同じ
if-else文後の処理
```

条件式がtrueなのでif文ブロック内の処理が実行されます。
そして、elseブロック内は実行されず、if文ブロック外の処理が実行される。という流れになります。



**条件式がfalseの場合。**

```java:ifがfalseの例
String name1 = "クリスティアーノ・ロナウド";
String name2 = "リオネル・メッシ";
if (name1 == name2) {
  System.out.println("name1とname2は同じ");
} else {
  System.out.println("name1とname2は同じではない");
}
System.out.println("if-else文後の処理");
```

実行結果は以下になります。


```text:実行結果
name1とname2は同じではない
if-else文後の処理
```

条件式がfalseなのでif文ブロック内の処理が実行されず、else文ブロックの処理が実行されています。
そして、if文ブロック外の処理が実行される。という流れになります。

これで条件式がfalseの場合の処理を実装することが出来ます。

#else if文

今までは条件式が１つだけでしたが、else if文を用いる事で複数の条件式を使うことが出来ます。

```text:構文
if( 条件式1 ) { 
  処理1
} else if ( 条件式2 ) {
  処理2
} else {
  処理3
};
```

処理1は条件式1がtrueの時に実行され、処理2は条件式2がtrueの時に実行され、処理3は1つ目と2つ目の条件式がfalseの時に実行されます。

**else if文は上から順に条件式が評価され、ある条件がtrueであった場合にそのブロック内の処理文のみを実行します。**


例えば、**条件式ifがtrueの場合。**

```java:ifがtrueの例
String color = "red";
if (color == "red") {
  System.out.println("colorはred");
} else if (color == "yellow") {
  System.out.println("colorはyellow");
} else {
  System.out.println("colorはredでもyellowでもない");
  System.out.println("colorは" + color);
}
System.out.println("else ifの例");
```

実行結果は以下になります。

```text:実行結果
colorはred
else ifの例
```

1つ目の条件式がtrueなのでif文ブロック内の処理が実行されます。
そして、else if、elseブロック内は実行されず、if文ブロック外の処理が実行される。という流れになります。

次に、**条件式else ifがtrueの場合。**

```java:else-ifがtrueの例
String color = "yellow";
if (color == "red") {
  System.out.println("colorはred");
} else if (color == "yellow") {
  System.out.println("colorはyellow");
} else {
  System.out.println("colorはredでもyellowでもない");
  System.out.println("colorは" + color);
}
System.out.println("else ifの例");
```

実行結果は以下になります。

```text:実行結果
colorはyellow
else ifの例
```

1つ目の条件式がfalseなのでif文ブロック内の処理が実行されません。
そして、2つ目の条件式がtrueなのでelse if文ブロック内の処理が実行されます。
elseブロック内は実行されず、if文ブロック外の処理が実行される。という流れになります。

**最後に条件式の全てがfalseの場合。**

```java:条件式全てがfalseの例
String color = "blue";
if (color == "red") {
  System.out.println("colorはred");
} else if (color == "yellow") {
  System.out.println("colorはyellow");
} else {
  System.out.println("colorはredでもyellowでもない");
  System.out.println("colorは" + color);
}
System.out.println("else ifの例");
```

実行結果は以下になります。

```text:実行結果
colorはredでもyellowでもない
colorはblue
else ifの例
```

1つ目、2つ目と条件式の結果がfalseなので、elseブロック内の処理が実行されます。
そして、if文ブロック外の処理が実行される。という流れになります。

これで複数の条件判定によって処理を分けることが出来るようになります。


#三項演算子

条件式の結果に応じた式を実行する演算子です。

```text:構文
条件式 ? 式１ : 式2;
```

条件式がtrueを返した場合は式1を実行し、falseを返した場合は式2を実行します。

例えば、**条件式がtrueの場合。**

```java:三項演算子の例
String name = "yamada";
String str = "名前の長さは";
str += name.length() >= 4 ?  "4以上です" : "3以下です";
System.out.println(str);
```

実行結果は以下になります。

```text:実行結果
名前の長さは4以上です
```

`name.length() >= 4`が条件式になります。
trueであれば、`4以上です`が、falseであれば`3以下です`がstrに格納されている文字列と結合されます。


同じ処理をif-else文で記述すると以下の様になります。

```java:if-elseの場合
String name = "yamada";
String str = "名前の長さは";
if (name.length() >= 4) {
  str += "4以上です";
} else {
  str += "3以下です";
}
System.out.println(str);
```

三項演算子の方がif-else文で記述するよりスッキリ書けますね。


#switch文

式の評価結果と定数を比較して、一致した場合に処理が実行される。という多分岐処理を行うための方法です。


```text:構文
switch ( 式 ) {
  case 定数1:
    処理1;
    break;
  case 定数2:
    処理2;
    break;
  default:
    処理3;
}
```

式の結果が定数1と一致していれば処理1が実行され、定数2と一致していれば処理2が実行されます。
一致するものがない場合、default以下の処理が実行されます。（defaultの記述は任意です）


```java:switch文の例
String color = "blue";

switch (color) {
  case "red":
    System.out.println("colorはred");
    break;
  case "yellow":
    System.out.println("colorはyellow");
    break;
  case "blue":
    System.out.println("colorはblue");
    break;
  default:
    System.out.println("colorは" + color);
    break;
}
```

実行結果は以下になります。

```text:実行結果
colorはblue
```

式の結果は"blue"という文字列であり、3つ目のcaseと一致しています。
よって、その中の処理が実行されます。

##switch文の注意点

###式のデータ型

switch文の式に記述可能な値は、**char、byte、short、int、そのラッパークラス、enum、String**のいずれかのデータ型の値ではないといけません。

それ以外の型が指定されているとコンパイルエラーになります。

```java:switch文の式のエラー
double d = 2.0;
switch (d) { // Cannot switch on a value of type double. Only convertible int values, strings or enum variables are permitted
  // 省略
}
```

###式の結果

式のデータ型を守っていたとして式の結果が**null**であった場合、コンパイルは成功しても実行時に例外が発生してしまいます。

```java:switch文の式の例外発生
String ex = null;
switch (ex) {
  case "a":
    System.out.println("a");
    break;
  case "b":
    System.out.println("b");
    break;
  default:
    System.out.println("nothing");
    break;
}
```

```text:実行結果
Exception in thread "main" java.lang.NullPointerException
        at Condition.main(Condition.java:102)
```

###()内で演算子を使う

()内で計算をしても問題はないです。

足し算や、

```java:()で計算の例
int a = 0;
switch (a + 1) {
  case 0:
    System.out.println("0");
    break;
  case 1:
    System.out.println("1");
    break;
  case 2:
    System.out.println("2");
    break;
}
```

```text:実行結果
1
```

デクリメントなど。

```java:()で計算の例2
int a = 0;
switch (--a) {
  case 0:
    System.out.println("0");
    break;
  case 1:
    System.out.println("1");
    break;
  default:
    System.out.println("該当数字はないです");
    break;
}
```

```text:実行結果
該当数字はないです
```

ただ、()内で変数を宣言するとコンパイルエラーになります。

```java:()で変数宣言してエラー
switch (int a = 0;) {
  case 0:
    System.out.println("0");
    break;
  case 1:
    System.out.println("1");
    break;
  case 2:
    System.out.println("2");
    break;
}
```

###caseで指定する値

①式の結果のデータ型とcaseで指定しているデータ型が一致していなければコンパイルエラーとなります。

```java:caseで指定する値のエラー
int num = 10;
switch (num) {
  case "0": // Type mismatch: cannot convert from String to int
    System.out.println("0");
    break;
  case "1": // Type mismatch: cannot convert from String to int
    System.out.println("1");
    break;
  case "2": // Type mismatch: cannot convert from String to int
    System.out.println("2");
    break;
}
```


②リテラル、定数ではない場合、コンパイルエラーとなります。

```java:caseで指定する値のエラー2
int num = 10;
int a = 1;
int b = 2;
switch (num) {
  case a: // case expressions must be constant expressions
    System.out.println("1");
    break;
  case b: // case expressions must be constant expressions
    System.out.println("2");
    break;
  default:
    System.out.println("nothing");
    break;
}
```

この場合、変数であるaとbをcaseに指定しているためエラーになります。
final修飾子を付与して定数化するか、リテラルを指定しましょう。

```java:caseで指定する値のエラー2修正ver
int num = 10;
final int a = 1;

switch (num) {
  case a:
    System.out.println("1");
    break;
  case 2:
    System.out.println("2");
    break;
  default:
    System.out.println("nothing");
    break;
}
```

③nullを指定するとコンパイルエラーとなります。

```java:caseで指定する値のエラー3
String name = "田中";

switch (name) {
  case "山田":
    System.out.println("山田");
    break;
  case null: // case expressions must be constant expressions
    System.out.println("null");
    break;
}
```

④break文の有無

**break;**というワードで、`処理が実行された後にswitch文から抜けています。`
もし忘れてしまっていた場合は次のcaseとの比較を初めてしまうので気をつけましょう。

```java:breakを忘れた時
int num = 10;

switch (num) {
  case 0:
    System.out.println("0");
    break;
  case 10:
    System.out.println("10");
    // break;を書き忘れている
  default:
    System.out.println("nothing");
    break;
}
```

case 10 の時の処理が実行された後、break文がないためdefaultの処理も実行してしまいます。

```text:実行結果
10
nothing
```

意図せぬ実行結果になってしまわないよう注意しましょう。

#終わりに

プログラムの処理手順として条件に応じて処理を分岐させる方法を学びました。
ソースコードの可読性などを考慮して、状況によって使い分けていきたいですね。


#参考サイト

**[処理の分岐](https://java.keicode.com/lang/flow.php)**
**[Javaのswitch文](https://morizyun.github.io/java/basic-switch.html)**