【Java入門】繰り返し処理について（while、do-while、for、拡張for、break、continue）

#目的

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/194cdc73a29bddade0a4)
・繰り返し処理 ←今ここ
・クラスについて（準備中）
・抽象クラス（準備中）
・インターフェース（準備中）
・カプセル化（準備中）
・モジュールについて（準備中）
・[例外処理について](https://qiita.com/morioheisei/items/d25d2b67e7530c1aab9d)
・[ラムダ式について](https://qiita.com/morioheisei/items/2bfcc3d8d8440b00e6a9)
・[Stream APIについて](https://qiita.com/morioheisei/items/3a7be38b4d3ef712ccb2)


#繰り返し処理とは

とある処理を`条件が成立している間`や`回数を指定して`、繰り返し処理をさせる事です。

```java:
int a = 0;
System.out.println("a => " + a);
a += 1;
System.out.println("a => " + a);
a += 1;
System.out.println("a => " + a);
```

上記の様なaを出力、+1して再度出力といった一連の処理も繰り返し処理によってスッキリ記述する事が可能です。

繰り返し処理は**ループ**とも呼ばれ、本記事では`while文、do-while文、for文、拡張for文`を取り上げます。


#while文

**指定された条件が成立する(true)間**、繰り返し処理を行います。

```text:構文
while( 条件式 ) {
  処理文; // 条件式がtrueの場合、実行される
}
```

whileの後の条件式は、`boolean値(true,false)を返す式`ではないといけません。

```java:while文の例
int num = 0;
while(num < 5) {
  System.out.println("num => " + num);
  num++;
}
```

```text:実行結果
num => 0
num => 1
num => 2
num => 3
num => 4
```

冒頭でも出てきた変数を出力、+1して再度出力といった一連の処理をスッキリ記述する事が出来ています。
`numが5未満の間この処理は繰り返され`、ループ毎にインクリメントされた**numが5になった時**、
条件判定時にfalseが返されるためwhile文は終了します。

##while文の注意点

###無限ループ

繰り返し処理が止まる事なく実行され続けてしまう事があります。
以下の点に注意しましょう。

```java:無限ループの例1
int num = 0;
while(num < 5) {
  System.out.println("num => " + num);
  num++;
}
```

このコードで`num++`の記述がなかった場合、num変数は0のままなので
条件式`num < 5`はtrueを返し続けるため、**無限ループ**となってしまいます。


```java:無限ループの例2
int num = 0;
while(true) {
  System.out.println("num => " + num);
  num++;
}
```

次に、条件式のところで`while(true)`をしてしまった場合。
これも常にtrueと返されるので**無限ループ**となってしまいます。

無限ループになってしまわない為(ループから抜ける為)に使われる**繰り返し制御文**は別記事にて説明します。そちらも一緒に覚えておきましょう。

###ループが始まらない

```java:ダメな例
while(false) {
  // 処理
}
```

条件式を`while(false)`とすると、処理に入る事が出来ない為コンパイルエラーとなります。

###何も出力されない

エラーにもならないのに何も出力されない時もあります。

```java:何も出力されない例
int num = 0;
while(num > 0) {
  System.out.println("num => " + num);
  num--;
}
```

上記の実行結果は何も出力されません。
whileの条件が0より大きいかを比較している為、いきなりfalseが返されループの中に入る事なく処理が終わってしまうからです。

num変数を1以上にするとループ内の処理が実行されます。

```java:改善案
int num = 3;
while(num > 0) {
  System.out.println("num => " + num);
  num--;
}
```

```text:実行結果
num => 3
num => 2
num => 1
```

#do-while文

while文と同様に**指定された条件が成立する(true)間**、繰り返し処理を行います。

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

while文と同様で条件式は、`boolean値(true,false)を返す式`ではないといけません。

```java:do-while文の例
int num = 0;
do {
  System.out.println("num => " + num);
  num++;
}while(num < 5);
```

```text:実行結果
num => 0
num => 1
num => 2
num => 3
num => 4
```

`numが5未満の間この処理は繰り返され`、ループ毎にインクリメントされた**numが5になった時**、
条件判定時にfalseが返されるためdo-while文は終了します。


#while文とdo-while文の違い

条件判定が行われるタイミングが違います。

while文では**先に条件判定が行われる**ので、前述の通り処理が実行されない場合もあります。
しかし、do-while文では条件判定よりも先にdoブロックがあり**後で条件判定が行われます**。よって条件に関係なく1度は処理が実行されます。

```java:条件判定の例_while
int num = 0;
while(num > 0) {
  System.out.println("while_num => " + num);
  num--;
}
```

上記のwhile文では何も出力されません。


```java:条件判定の例_do-while
int num = 0;
do {
  System.out.println("do-while_num => " + num);
  num--;
}while(num > 0);
```

```text:実行結果
do-while_num => 0
```

do-while文では1度だけ処理が実行され、条件式がfalseである為do-while文を終了しています。

このような違いがある事に注意しましょう。

#while文とdo-while文の共通点


while文もdo-while文も処理する文が1つしかない場合は`{}`を省略して記述する事が可能です。

```java:whileの場合
int num = 0;
while (num < 5) System.out.println("num => " + num++);
```

```text:実行結果
while_num => 0
while_num => 1
while_num => 2
while_num => 3
while_num => 4
```

```java:do-whileの場合
int num = 5;
do
  System.out.println("do-while_num => " + num--);
while(num > 0);
```

```text:実行結果
do-while_num => 5
do-while_num => 4
do-while_num => 3
do-while_num => 2
do-while_num => 1
```

#for文

for文も条件判定がtrueである間、繰り返し処理が実行されます。

while文、do-while文では、`()`には条件式のみ記述していましたが、
for文の`()`内では、**カウント変数の宣言、初期化**、**条件式**、**カウント変数の更新**を行います。

```text:構文
for(式1; 式2; 式3;) {
  処理文;
}
```

for文の流れは以下の通りになります。

・式1で繰り返し回数を示す変数(カウンタ変数)を宣言、初期化。
・式2で条件判定を行う。
・条件判定がtrueの場合、処理文が実行される。
・処理が実行された後、式3でカウンタ変数の更新が行われる。
・再び式2で条件判定を行う。
・式2での判定がfalseの場合、for文を終了する。

実際にコードと実行結果を見てみましょう。

```java:for文の例
for(int i = 0; i < 5; i++) {
  System.out.println("i => " + i);
}
```

```text:実行結果
i => 0
i => 1
i => 2
i => 3
i => 4
```

このようにfor文でもwhile文、do-while文と同様の処理を記述する事が出来ます。


##for文の省略した記述方法

以下の様な記述方法でもfor文は実行されます。

###カウンタ変数の宣言、初期化の省略

```java:for文の省略した記述方法_例1
int num = 0;
for(; num < 5; num++) {
  System.out.println("num => " + num);
}
```

```text:実行結果
num => 0
num => 1
num => 2
num => 3
num => 4
```

for文でカウンタ変数の宣言、初期化を行うのではなく、事前に行っています。
この様な記述方法でも動作します。


###カウンタ変数の更新の省略

```java:for文の省略した記述方法_例2
for(int num = 0; num < 5; ) {
  System.out.println("num => " + num++);
}
```

```text:実行結果
num => 0
num => 1
num => 2
num => 3
num => 4
```

処理文内にてnum変数をインクリメントして更新しています。
この様な記述方法でも動作します。

インクリメントを忘れてしまうと**無限ループ**になってしまうので注意しましょう。


##for文の様々な記述方法と注意点

for文の`()`内に記述する方法はいくつか規則があるのでみていきましょう。

###式1は文である必要がある

以下は式1に変数を記述しているだけなのでエラーになります。

```java:コンパイルエラー
int num = 1;
for(num; num < 5; num++) {
  System.out.println("num => " + num);
}
```

以下の様に式1は文である必要があります。

```java:改善案
int num = 1;
for(num += 1; num < 5; num++) {
  System.out.println("num => " + num);
}
```

```text:実行結果
num => 2
num => 3
num => 4
```

###式1の宣言式は1つのみ

以下は式1で複数宣言式を記述しているためエラーになります。

```java:コンパイルエラー
for(int i = 0, int = j = 0; i < 5; i++) {
  System.out.println("i => " + i);
  System.out.println("j => " + (j+=2));
  System.out.println("===============");
}
```

以下の様に式1での宣言式は1つではないといけません。

```java:改善案
for(int i = 0, j = 0; i < 5; i++) {
  System.out.println("i => " + i);
  System.out.println("j => " + (j+=2));
  System.out.println("===============");
}
```

```text:実行結果
i => 0
j => 2
===============
i => 1
j => 4
===============
i => 2
j => 6
===============
i => 3
j => 8
===============
i => 4
j => 10
===============
```

###式3も複数入れる事が可能

カンマで式を区切る事で、カウンタ変数の更新処理も複数入れる事が出来ます。
上記のコードを書き換えてみます。

```java:式3に複数入れる例
for(int i = 0, j = 2; i < 5; i++, j+=2) {
  System.out.println("i => " + i);
  System.out.println("j => " + j);
  System.out.println("===============");
}
```

```text:実行結果
i => 0
j => 2
===============
i => 1
j => 4
===============
i => 2
j => 6
===============
i => 3
j => 8
===============
i => 4
j => 10
===============
```

同様の結果を出力する事が出来ます。


#拡張for文

for文をさらに便利にした記述方法として、配列やコレクションの全要素を順番に取り出して処理をする場合に使用します。

```text:構文
for(変数宣言 : 参照変数名) {
  処理文;
}
```

実際にコードと実行結果を見てみましょう。

```java:拡張for文の例
int[] numbers = {1, 2, 3, 4, 5};
for(int val : numbers) {
  System.out.println(val);
}
```

```text:実行結果
val => 1
val => 2
val => 3
val => 4
val => 5
```

`numbersの要素を１つずつval変数へ代入し出力`という流れを繰り返し行っています。

同じ処理をfor文で記述して比較してみましょう。

```java:for文の場合
int[] numbers = {1, 2, 3, 4, 5};
for(int i = 0; i < numbers.length; i++) {
  System.out.println("numbers[" + i + "] => " + numbers[i]);
}
```

```text:実行結果
numbers[0] => 1
numbers[1] => 2
numbers[2] => 3
numbers[3] => 4
numbers[4] => 5
```

拡張for文で記述する事により、カウンタ変数の宣言、初期化や条件式、カウンタ変数の更新処理の記述が不要になります。
for文に比べてシンプルに記述する事が可能です。

##拡張for文の注意点

変数宣言する型は、参照する変数の型と一致していなければいけません。
以下はエラーになります。

```java:コンパイルエラー
String[] names = {"田中", "佐藤", "鈴木"};
for(int val : names) {
  System.out.println("name => " + val);
}
```

**参照変数がString型の配列であるのに対して**、変数宣言が`int型`である為です。

参照変数と各要素を受け取る変数の型は一致合わせるよう注意しましょう。

```java:改善案
String[] names = {"田中", "佐藤", "鈴木"};
for(String val : names) {
  System.out.println("name => " + val);
}
```

```text:実行結果
name => 田中
name => 佐藤
name => 鈴木
```

#for文と拡張for文の共通点

**for文も拡張for文も処理する文が１つしかない場合は`{}`を省略して記述する事が可能です。**

```java:for文の場合
for(int i = 0; i < 3; i++)
  System.out.println("i => " + i);
```

```text:実行結果
i => 0
i => 1
i => 2
```

```java:拡張for文の場合
int[] numbers = {10, 20, 30};
for(int val : numbers)
  System.out.println("val => " + val);
```

```text:実行結果
val => 10
val => 20
val => 30
```

**ローカル変数型推論（var）の利用が可能です。**
(ローカル変数型推論については別記事にまとめようと思います。)

```java:for文の場合
for(var i = 0; i < 3; i++) {
  // 省略
}
```

```java:拡張for文の場合
for(var val : numbers) {
  // 省略
}
```

#繰り返し制御文とは

上述の繰り返し処理は、**条件式がtrueの間実行され続ける**というものでした。

特定の条件の時に繰り返し処理から抜けたいという時、繰り返し制御文である**break文**や**continue文**を使用します。

#break文

実行中の繰り返し処理を中断して抜け出す時、繰り返し文の無限ループから抜け出す時に使用します。
switch文のcase内でも使用します。

ループから抜けた後は次の処理を実行します。


```java:break文の例
for(int i = 0; ; i++) {
  if(i == 5) {
    break;
  }
  System.out.println("i => " + i);
}
System.out.println("for文の後の処理");
```

```text:実行結果
i => 0
i => 1
i => 2
i => 3
i => 4
for文の後の処理
```

式2を書き忘れているため、条件式がありません。よって無限ループになってしまいます。
しかし、`if(i == 5)`のブロック内に`break;`がある事で、**iが5になった時ループを抜ける事になります。**

そしてfor文の後の処理を実行しています。

#continue文

実行中の繰り返し処理を中断するのではなくその処理だけスキップして、条件式の判定を行わせ更に繰り返し処理を続ける時に使用します。

```java:continue文の例
for(int i = 0; i < 10; i++) {
  if((i % 3) == 0) {
    continue;
  }
  System.out.println("i => " + i);
}
System.out.println("for文の後の処理");
```

```text:実行結果
i => 1
i => 2
i => 4
i => 5
i => 7
i => 8
for文の後の処理
```

`if((i % 3) == 0)`のブロック内に`continue;`がある事で、
**iを3で割って余りが0の時に処理をスキップしています。(式2の条件判定がtrueである限りループは続く)**

そして、for文が終了した後はその後の処理を実行しています。

#break文とcontinue文の共通点 ラベル

繰り返し文がネストしている場合(複数ある場合)、内側の繰り返し文に記述されたbreak文やcontinue文は、内側の繰り返し処理のみ適用されます。
外側のループからも抜けたい、スキップしたい場合、**ラベル**を使用する事で可能です。

```text:構文
ラベル名:
for(式1; 式2; 式3;) {
  for(式1; 式2; 式3;) {
    break 又は continue ラベル名;
  }
}
```

break文とcontinue文でそれぞれラベルの有無で処理がどう違うかみてみましょう。

##break文の場合

ラベルを使用しない場合は以下の様になります。
iとjが1の時にループを終えたい。という想定で実装をしています。

```java:ラベル無し
for(int i = 0; i < 3; i++) {
  for(int j = 0; j < 3; j++) {
    System.out.println("i: " + i + ", j: " + j);
    if(i == 1 && j == 1) {
      break;
    }
  }
}
```

```text:実行結果
i: 0, j: 0
i: 0, j: 1
i: 0, j: 2
i: 1, j: 0
i: 1, j: 1
i: 2, j: 0
i: 2, j: 1
i: 2, j: 2
```

ループは終わらず、iがインクリメントされて次のループにいっています。

ラベルを使用した場合は以下の様になります。

```java:ラベル有り
loop:
for(int i = 0; i < 3; i++) {
  for(int j = 0; j < 3; j++) {
    System.out.println("i: " + i + ", j: " + j);
    if(i == 1 && j == 1) {
      break loop;
    }
  }
}
```

```text:実行結果
i: 0, j: 0
i: 0, j: 1
i: 0, j: 2
i: 1, j: 0
i: 1, j: 1
```

iとjが1の時に外側のループも抜ける事が出来ています。


##continue文の場合

ラベルを使用しない場合は以下の様になります。
iとjが1の時に、iをインクリメントした次のループへスキップしたい。という想定で実装をしています。

```java:ラベル無し
for(int i = 0; i < 3; i++) {
  for(int j = 0; j < 3; j++) {
    if(i == 1 && j == 1) {
      continue;
    }
    System.out.println("i: " + i + ", j: " + j);
  }
}
```

```text:実行結果
i: 0, j: 0
i: 0, j: 1
i: 0, j: 2
i: 1, j: 0
i: 1, j: 2
i: 2, j: 0
i: 2, j: 1
i: 2, j: 2
```

iとjが1の時だけしかスキップされていません。

ラベルを使用した場合は以下の様になります。

```java:ラベル有り
loop2:
for(int i = 0; i < 3; i++) {
  for(int j = 0; j < 3; j++) {
    if(i == 1 && j == 1) {
      continue loop2;
    }
    System.out.println("i: " + i + ", j: " + j);
  }
}
```

```text:実行結果
i: 0, j: 0
i: 0, j: 1
i: 0, j: 2
i: 1, j: 0
i: 2, j: 0
i: 2, j: 1
i: 2, j: 2
```

iとjが1の時に、iをインクリメントした次のループへスキップ出来ています。

この様に`ラベルを用いる事で、多重ループから抜け出したり、スキップしたりする事が可能`になります。



#終わりに

同じ処理を繰り返し行うための構文、条件に応じて処理を中断、スキップさせるための繰り返し制御文を学びました。
使い分ける事によってコードをスッキリ記述する事ができ、同じ処理を何度も書かなくて済むので使いこなしていきたいですね。


#参考サイト

**[【Java入門】繰り返し処理をマスターしよう！(forとwhile)](https://programming-study.com/technology/java-loop/)**
**[拡張for文(for-each文)](https://www.javadrive.jp/start/for/index8.html)**