java.svg

【Java】ループ処理

Java

for 文

String[] fruits = {"リンゴ", "オレンジ", "バナナ"};
for (int i = 0; i < fruits.length; i++) {
  System.out.println(fruits[i]);
}

おそらく最初に覚えるであろう、基本的なループ処理です。

for 文は、主に以下の用途で使用されます。

  • 決まった回数のループ処理
  • インデックスが必要な配列、コレクションのループ処理
  • ループ毎に一定の変化を行うループ処理

for 文には、初期化式、条件式、変化式の 3 つの要素を順に設定します。

初期化式

初期化式では、ループで使用する変数のループ開始時の値を設定します。

変数は事前に用意してもよいのですが、上例のint i = 0のように初期値として変数を定義することができます。 この場合、変数のスコープは for 文の処理内となります。 そのため for 文の処理ないでしか使用しない場合はこちらを使用します。

//変数自体を定義したfor文
for (int i = 0; i < fruits.length; i++) {
  //変数 i はこの中でのみ使用可能
}

//事前に変数を用意したfor文
int j = 0;
for (j = 0; j < fruits.length; j++) {
  //変数 j はこの中で使用可能
}
//変数 j はfor文の外でも使用可能
//for文によって値が変化していることに注意

条件式

条件式には、ループ処理を継続するための条件を設定します。条件式を満たさなくなった場合にループが終了します。

条件式を設定しなかった場合は、永久ループになります。

for (int i = 0; ; i++) {
  //永久ループ
}

変化式

変化式には、ループが終わるたびにどのような処理を行うかを設定します。

上例では、変数iをインクリメントしています。

複数変数

使用する頻度は少ないかもしれませんが、以下のようにカンマで区切ることで複数の変数を使用できます。

for (int i = 0; j = 1; i < fruits.length; i++, j += 2) {
  //...
}

while 文、do-while 文

//while文
String[] fruits = {"リンゴ", "オレンジ", "バナナ"};
int i = 0;
while (i < fruits.length) {
  System.out.println(fruits[i]);
  i++;
}

//do-while文
int j = 0;
do {
  System.out.println(fruits[j]);
  j++;
} while (j < fruits.length);

while 文、do-while 文は条件式のみを設定します。条件式の考え方は for 文と同じです。

for 文と同じく終了条件を設定しなかった場合は永久ループとなります。

while () {
  //...
}

do {
  //...
} while();

while 文と do-while 文の違いは終了条件の判定のタイミングです。

while 文はループ処理の開始前に行い、do-while 文はループ処理の終了後に行います。 つまり、do-while 文は終了条件を満たしていたとしても必ず 1 度はループ処理が実行されます。

int i = 3;
while (i < 3) {
  //これは実行されない
}

do {
  //これは1回実行される
} while (i < 3)

do-while 文はコーディング規約によって使用を禁止されているケースもしばしば見かけます。

拡張 for 文

String[] fruits = {"リンゴ", "オレンジ", "バナナ"};
for (String fruit : fruits) {
  System.out.println(fruit);
}

拡張 for 文では、配列またはコレクション(Listなど)の要素を順に指定した変数に格納します。 ループ処理は、要素数分行われます。

インデックスが不要な配列、コレクションのループ処理の場合は、for 文ではなく拡張 for 文を利用するほうがよいでしょう。

上例ではfruitsの要素が順にfruitに格納されます。

forEach (Stream API)

String[] fruits = {"リンゴ", "オレンジ", "バナナ"};
Arrays.stream(fruits)
      .forEach(fruit -> {
        System.out.println(fruit);
      });

Java8 から使用できる方法です。

考え方は拡張 for 文と同じで、配列やコレクションの要素を順に変数に格納します。 ただし、配列はそのままでは使用できないためstreamに変換してからループ処理を行います。

ループ処理はラムダ式で定義します。ラムダ式についてはこの記事では割愛します。

forEach はデメリットも多く、仕様をよく理解せずに利用すると大変苦労します。無理に使用せず、拡張 for 文を使用することをオススメします。

ループ制御

これから説明することはforEachでは使用できません。

continue

for (String fruit : fruits) {
  if ("オレンジ".equals(fruit)) {
    continue;
  }
  System.out.println(fruit);
}
//リンゴ、バナナが出力

continueを指定すると、continueの後に定義された処理は実行されず、次のループ処理が行われます。

break

for (String fruit : fruits) {
  if ("オレンジ".equals(fruit)) {
    break;
  }
  System.out.println(fruit);
}
//リンゴのみ出力

breakは、ループを強制的に終了させたい場合に使用します。

上例では、要素の値がオレンジの場合にループを終了させているため、リンゴのみ出力されます。

ラベル付きループ

ループ処理にはラベルを付与することができます。

これまでの例とは異なりますが、以下のような多重ループの際にcontinuebreakと組み合わせて使用します。

loop: for (int i = 0; i < 3; i++) {
  System.out.println("Start: " + i);
  for (int j = 0; j < 3; j++) {
    if (i * j == 1) {
      continue loop;
    }
    System.out.println(String.format("%d, %d", i, j ));
  }
  System.out.println("End: " + i);
}

//【出力結果】
//Start: 0
//0, 0
//0, 1
//0, 2
//End: 1
//Start: 1
//1, 0
//Start: 2
//2, 0
//2, 1
//2, 2
//End: 2

continueと組み合わせる場合、continue ラベル名とすることでラベルのついたループに対し、次のループ処理を実行するようにします。

loop: for (int i = 0; i < 3; i++) {
  System.out.println("Start: " + i);
  for (int j = 0; j < 3; j++) {
    if (i * j == 1) {
      break loop;
    }
    System.out.println(String.format("%d, %d", i, j ));
  }
  System.out.println("End: " + i);
}

//【出力結果】
//Start: 0
//0, 0
//0, 1
//0, 2
//End: 1
//Start: 1
//1, 0

breakと組み合わせる場合、break ラベル名とすることでラベルのついたループ処理を終了させます。

ラベルは while 文や拡張 for 文でも使用できます。