Javaイテレータ:コレクションの要素を順番に処理しよう!

docs

前回はJavaのコレクションフレームワークについて学んだよね。リストやセット、マップといった便利なデータ構造を使って、たくさんのデータを効率よく扱えるようになったはず。

コレクションフレームワークって何? | ToolDocs

でも、コレクションに格納したデータを一つずつ取り出して処理したいときってどうするんだろう? 例えば、ArrayListに入った生徒の名前を全員表示したり、HashSetに入った商品の値段を合計したり。そんなときに活躍するのが今回紹介するイテレータなんだ!

イテレータってなに?

イテレータは、コレクションの中身を順番に「ぐるぐる」と回って、要素を一つずつ取り出すための便利な道具だよ。イメージとしては、カゴに入ったミカンを一つずつ取り出して食べるような感じかな。

なんでこんな回りくどいことをするの?って思うかもしれないけど、これにはちゃんと理由があるんだ。コレクションには色々な種類があるって前回話したよね。ArrayListは順番があるし、HashSetは順番がない。それぞれのコレクションの内部構造に合わせて要素を取り出す方法を考えるのは大変だよね?

イテレータを使えば、コレクションの種類を意識せずに同じ方法で要素を取り出せるんだ。これはすごく便利だよね!

イテレータの基本的な使い方

イテレータの使い方はとってもシンプル。3つのステップで覚えられるよ。

  1. iterator() メソッドでイテレータを取得する
  2. hasNext() メソッドで次の要素があるか確認する
  3. next() メソッドで次の要素を取り出す

さっそくコードを見てみよう!

Java

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class IteratorExample {
    public static void main(String[] args) {
        // ① ArrayListを作成して要素を追加
        List<String> fruits = new ArrayList<>();
        fruits.add("りんご");
        fruits.add("みかん");
        fruits.add("バナナ");
        fruits.add("ぶどう");

        // ② イテレータを取得
        Iterator<String> iterator = fruits.iterator();

        // ③ ループで要素を一つずつ処理
        System.out.println("好きなフルーツ:");
        while (iterator.hasNext()) { // 次の要素があるか確認
            String fruit = iterator.next(); // 次の要素を取り出す
            System.out.println(fruit);
        }
    }
}

実行結果:

好きなフルーツ:
りんご
みかん
バナナ
ぶどう

どうかな? 簡単に要素を順番に取り出せたよね!

fruits.iterator()Iterator オブジェクトを取得して、while (iterator.hasNext()) でループを回しているんだ。hasNext()true を返している間は、まだ取り出せる要素があるってこと。そして iterator.next() で実際に要素を取り出しているよ。

paizaで実行した結果

remove() メソッドで要素を削除!

イテレータには、要素を取り出すだけでなく、コレクションから要素を削除する機能もあるんだ。ただし、ちょっと注意が必要だよ。

remove() メソッドは、next() メソッドで最後に取得した要素を削除するんだ。next() を呼び出す前に remove() を呼んだり、同じ要素に対して複数回 remove() を呼んだりするとエラーになるから気をつけよう。

例を見てみよう。

Java

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class IteratorRemoveExample {
    public static void main(String[] args) {
        List<String> items = new ArrayList<>();
        items.add("ペン");
        items.add("ノート");
        items.add("消しゴム");
        items.add("定規");

        Iterator<String> iterator = items.iterator();

        System.out.println("元のアイテムリスト:" + items);

        while (iterator.hasNext()) {
            String item = iterator.next();
            if (item.equals("ノート")) {
                iterator.remove(); // 「ノート」を削除
                System.out.println("「ノート」を削除しました。");
            }
        }
        System.out.println("変更後のアイテムリスト:" + items);

        // もう一度イテレータを試す(新しいイテレータが必要)
        Iterator<String> newIterator = items.iterator();
        System.out.println("\n再度イテレータで表示:");
        while (newIterator.hasNext()) {
            System.out.println(newIterator.next());
        }
    }
}

実行結果:

元のアイテムリスト:[ペン, ノート, 消しゴム, 定規]
「ノート」を削除しました。
変更後のアイテムリスト:[ペン, 消しゴム, 定規]

再度イテレータで表示:
ペン
消しゴム
定規

「ノート」だけが削除されたのがわかるよね。 もし、イテレータを使わずに for ループなどで要素を削除しようとすると、ループの途中でコレクションのサイズが変わってしまって、予期せぬエラー(ConcurrentModificationException など)が発生することがあるんだ。イテレータの remove() メソッドは、そういった問題を回避するための安全な方法なんだよ。

paizaで実行した結果

拡張for文(for-each文)との違い

Javaには、イテレータと似たようなことをもっと簡単に書ける**拡張for文(for-each文)**というものもあるって知ってた?

Java

import java.util.ArrayList;
import java.util.List;

public class EnhancedForLoopExample {
    public static void main(String[] args) {
        List<String> colors = new ArrayList<>();
        colors.add("赤");
        colors.add("青");
        colors.add("黄");

        System.out.println("拡張for文で表示:");
        for (String color : colors) { // これが拡張for文
            System.out.println(color);
        }
    }
}

実行結果:

拡張for文で表示:
赤
青
黄

paizaで実行した結果

拡張for文は、内部的にはイテレータを使っているんだけど、記述がすごくシンプルだよね。じゃあ、イテレータと拡張for文、どっちを使えばいいんだろう?

  • 要素を順番に「読み取るだけ」なら拡張for文がおすすめ!
    • コードが短く、読みやすい
    • シンプルに要素を巡回したいときに最適
  • 要素を読み取りながら「削除したい」ならイテレータが必要!
    • remove() メソッドを使いたい場合はイテレータ一択
    • コレクションの途中で要素の追加や削除をする場合は、イテレータを使わないと危険

使い分けを理解して、状況に応じて適切な方を選ぼうね!

ListIterator っていうのもあるよ!

コレクションの中でも、特に List インターフェースを実装しているもの(ArrayListやLinkedListなど)には、ListIterator という特別なイテレータが用意されているんだ。

ListIterator は、普通のイテレータに加えて、こんなことができるようになるよ。

  • 逆方向に要素をたどる (hasPrevious(), previous())
  • 要素を追加する (add())
  • 要素を置き換える (set())
  • 現在のインデックスを取得する (nextIndex(), previousIndex())

ちょっと高度だけど、リストの要素をより細かく操作したいときにすごく役立つから、頭の片隅に置いておくといいかもね。

Java

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class ListIteratorExample {
    public static void main(String[] args) {
        List<String> animals = new ArrayList<>();
        animals.add("犬");
        animals.add("猫");
        animals.add("うさぎ");

        ListIterator<String> listIterator = animals.listIterator();

        System.out.println("順方向に表示:");
        while (listIterator.hasNext()) {
            String animal = listIterator.next();
            System.out.println(animal);
            if (animal.equals("猫")) {
                listIterator.add("フェレット"); // 「猫」の後ろに「フェレット」を追加
            }
        }
        System.out.println("追加後のリスト:" + animals);

        System.out.println("\n逆方向に表示:");
        while (listIterator.hasPrevious()) { // 逆方向に進む
            String animal = listIterator.previous();
            System.out.println(animal);
        }
    }
}

実行結果:

順方向に表示:
犬
猫
うさぎ
追加後のリスト:[犬, 猫, フェレット, うさぎ]

逆方向に表示:
うさぎ
フェレット
猫
犬

「猫」の後に「フェレット」が追加され、さらに逆方向にもたどれるようになったのがわかるかな? 便利な機能がいっぱいだよね。

paizaで実行した結果

まとめ

今回はJavaのイテレータについて学んだよ。

  • イテレータはコレクションの要素を順番に処理するための便利な道具
  • hasNext() で次の要素があるか確認し、next() で要素を取り出す。
  • remove() メソッドで要素を安全に削除できる。
  • 要素を読み取るだけなら拡張for文が便利だけど、削除や複雑な操作をするならイテレータを使おう。
  • List コレクションには、さらに高機能なListIteratorがある。

イテレータは、Javaでコレクションを扱う上で必須の知識だから、しっかりマスターしてね!


前回の記事はこちらから → コレクションフレームワークって何? | ToolDocs

コメント

タイトルとURLをコピーしました