1. 序章

要素の反復処理は、コレクションに対して実行できる最も基本的な操作の1つです。

このチュートリアルでは、 Set の要素を反復処理する方法と、Listまたは配列の同様のタスクとどのように異なるかを見ていきます。

2. セット内の要素へのアクセスの取得

Set、は、 List や他の多くのコレクションとは異なり、シーケンシャルではありません。 それらの要素にはインデックスが付けられておらず、実装によっては、順序が維持されない場合があります。

つまり、セットの特定の要素についてその番号で尋ねることはできません。 そのため、通常のforループやその他のインデックスベースの方法を使用することはできません。

2.1. イテレータ

セットを反復処理する最も基本的で金属に近い方法は、すべてのSetによって公開されるiteratorメソッドを呼び出すことです。

Set<String> names = Sets.newHashSet("Tom", "Jane", "Karen");
Iterator<String> namesIterator = names.iterator();

次に、取得したイテレータを使用して、そのセットの要素を1つずつ取得できます。 最も象徴的な方法は、イテレータwhileループに次の要素を持っているかどうかを確認することです。

while(namesIterator.hasNext()) {
   System.out.println(namesIterator.next());
}

Java8で追加されたforEachRemainingメソッドを使用することもできます。

namesIterator.forEachRemaining(System.out::println);

これらのソリューションを混在させることもできます。

String firstName = namesIterator.next(); // save first name to variable
namesIterator.forEachRemaining(System.out::println); // print rest of the names

他のすべてのメソッドは、内部で何らかの方法でIteratorを使用します。

3. ストリームs

すべてのSetは、 spliterator()メソッドを公開します。 そのため、セットは簡単にStreamに変換できます。

names.stream().forEach(System.out::println);

豊富なStreamsAPI を活用して、より複雑なパイプラインを作成することもできます。 たとえば、セットの要素を1つの文字列にマッピング、ログ記録、および縮小してみましょう。

String namesJoined = names.stream()
    .map(String::toUpperCase)
    .peek(System.out::println)
    .collect(Collectors.joining());

4. 強化されたループ

単純なインデックス付きのforループを使用してSetを反復処理することはできませんが、Java5で導入された拡張ループ機能を使用できます。

for (String name : names) {
    System.out.println(name);
}

5. インデックスで反復する

5.1. 配列への変換

Set はインデックス付けされていませんが、人為的にインデックスを追加することができます。 考えられる解決策の1つは、セットを配列のようなより親しみやすいデータ構造に単純に変換することです。

Object[] namesArray = names.toArray();
for (int i = 0; i < namesArray.length; i++) {
    System.out.println(i + ": " + namesArray[i]);
}

配列への変換だけで、Setが1回繰り返されることに注意してください。 したがって、複雑さの観点から、Setを2回繰り返します。 パフォーマンスが重要な場合、これは問題になる可能性があります。

5.2. インデックスで圧縮

もう1つの方法は、インデックスを作成し、Setで圧縮することです。 バニラJavaでそれを行うことはできますが、そのためのツールを提供するライブラリがあります。

たとえば、Vavrのストリームを使用できます。

Stream.ofAll(names)
  .zipWithIndex()
  .forEach(t -> System.out.println(t._2() + ": " + t._1()));

6. 概要

このチュートリアルでは、Setインスタンスの要素を反復処理するさまざまな方法を確認しました。 イテレータ、ストリーム、ループの使用法と、それらの違いについて説明しました。

いつものように、例はGitHubを介して利用できます。