リストのイテレートについて、シンプルなリストを使って書き方を見ていきます。
今回は以下の文字列のリストを使います。
final List<String> months =
Arrays.asList("January", "February", "March", "April", "May", "June", "July", "Augast", "September", "October", "November", "December");
これらの要素を順番に標準出力させたいだけです。
命令型のスタイル
まずは、for ループを使ってみます。
for ループは命令型のスタイルで、外部イテレータです。
命令型のスタイルでは、「どのように」処理を行うかの多くをプログラマ側で考える必要があります。
1. for ループ(インデックス指定)
特に難しいことはないと思います。1番目の要素から順番に出力しています。
インデックスをわざわざ一つずつインクリメントしながら指定する必要があります。
for (int i = 0; i < months.size(); i++) {
System.out.println(months.get(i));
}
2. for ループ(インデックス指定なし)
インデックスが不要な場合は、単純な for ループよりも高度な制御構文が Java には用意されています。
裏では Iteratorインタフェースが適用されており、hasNext() と next() メソッドが呼び出されています。そのため、リストのサイズを用いて、ループの最後をプログラマ側で指定する必要はありません。
for (final String month : months) {
System.out.println(month);
}
関数型のスタイル
Java8 から Iterable インターフェースに forEach メソッドが追加されています。
関数型のスタイルで、内部イテレータです。
関数型のスタイルでは、「何を」行うのかを考えることに集中しやすくなります。
3. foreach() Consumer
foreach() は Consumer 型を引数に取りますが、このインスタンスは accept() メソッドで受け取った引数を処理します。
リスト内の各要素が一つずつ、accept() メソッドに渡されていきますので、その中で標準出力させています。
months.forEach(new Consumer<String>() {
public void accept(final String month) {
System.out.println(month);
}
});
4. foreach() Lambda
Lambda 式を使うことで、匿名内部クラス(Consumer インスタンス以下)を置き換えることができます。
months.forEach((final String month) -> System.out.println(month));
Javaコンパイラは型推論ができるため、以下のように省略が可能となります。ただし、この場合は final が外れてしまいイミュータブルな引数ではなくなります。
months.forEach(month -> System.out.println(month));
5. foreach() メソッド参照
メソッド参照は Java8 からの機能で、クラス名::メソッド名 が基本形になります。
すでに定義済みのメソッドを引数の指定を省略して実行できるため、更に省略した形になります。
months.forEach(System.out::println);