![]()
【Java入門 実用編】List 以外での Stream API の利用 | コレクションクラスの活用
2026.02.20
前回までの記事では、Java のコレクションとして最も利用頻度の高い List の活用方法や、Stream API を利用したソートなどの方法について解説しました。特に Java 8 以降で利用できる Stream API は、直観的なコーディングで元のデータを破壊することなく安全に「絞り込み(filter)」や「変換(map)」などの処理を簡潔に記述できる強力な機能です。
当記事では、List 以外のコレクションにおける Stream API の具体的な利用方法と実践的な使いどころについて解説します。

目次
Set インターフェイスで Stream を利用する
要素の重複を許さない Set インターフェースを実装したコレクションは、Listと同様に Collection インターフェイスを継承しているため、stream メソッドを呼び出すことで、Stream API を利用することができます。
ここでは、用途の異なる2つの実装クラス(HashSet と LinkedHashSet)を用いて、Set インターフェイスでの Stream の活用方法を紹介します。
HashSet クラスでの利用
HashSet クラスは「重複を許さず、順序も保証しない」という最も基本的な Set です。システムから収集した「一意のタグ一覧」や「重複のないユーザーID」などに対して、特定の条件を満たすものだけを抽出(フィルタリング)するケースで非常に役立ちます。
以下の例では、重複のないタグの集合から、さらに名前に "Java" を含むものだけを抽出して、新しい Set を作成します。
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
public class HashSetStreamSample {
public static void main(String[] args) {
// 抽出元データのSetの準備
Set<String> tags = new HashSet<>();
tags.add("Java");
tags.add("Spring");
tags.add("JavaScript");
tags.add("HTML");
System.out.println("元のHashSet: " + tags);
// Streamで条件抽出(フィルタリング)を行う
Set<String> javaTags = tags.stream()
.filter(tag -> tag.contains("Java")) // "Java"を含む要素だけ
.collect(Collectors.toSet()); // 再びSetとしてまとめる
System.out.println("抽出されたSet: " + javaTags);
}
}
実行結果:
元のHashSet: [Java, Spring, HTML, JavaScript]
抽出されたSet: [Java, JavaScript]LinkedHashSet クラスを利用
Set でも List と同じように要素をソートしたい場合、Stream API で sorted メソッドを利用して、簡単に要素のソートを行うことができます。 しかしソートした Stream を 一般的な Collectors.toSet メソッドを利用して新しい Set として作成してしまうと、内部的に通常の HashSet が生成されることが多く、並べ替えた順序が水の泡になってしまいます。
このような場合は、Stream での collect メソッドの呼び出し時に Collectors.toCollection メソッドを利用し、要素を格納するために生成する実装クラスを明示的に指定することで対応します。例えば「重複は排除したいけれど、ソートした順序は維持したままSetとして扱いたい」 ケースでは、挿入した順序を記憶する LinkedHashSet を利用することで以下のように実現できます。
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;
public class LinkedHashSetStreamSample {
public static void main(String[] args) {
// 順序がバラバラのHashSet
Set<String> fruits = new HashSet<>(Arrays.asList("Banana", "Apple", "Orange", "Grape"));
System.out.println(fruits+ " <- 元のHashSet");
// --------------------------------------------------
// 失敗例:通常の toSet() だと順序が失われる可能性が高い
// --------------------------------------------------
Set<String> wrongSet = fruits.stream()
.sorted() // 辞書順にソート
.collect(Collectors.toSet());
System.out.println( wrongSet + " <- Collectors.toSet() で回収");
// --------------------------------------------------
// 成功例:LinkedHashSet に格納して順序を保持する
// --------------------------------------------------
Set<String> sortedSet = fruits.stream()
.sorted() // 辞書順にソート
.collect(Collectors.toCollection(LinkedHashSet::new));
System.out.println(sortedSet + " <- Collectors.toCollection(LinkedHashSet::new) で回収");
}
}
実行結果:
[Apple, Grape, Orange, Banana] <- 元のHashSet
[Apple, Grape, Orange, Banana] <- Collectors.toSet() で回収
[Apple, Banana, Grape, Orange] <- Collectors.toCollection(LinkedHashSet::new) で回収"Deque(Queue) インターフェイスで Stream を利用する
ArrayDeque など、Queue または Deque インターフェイスを実装した、待ち行列を扱うコレクションも List や Set と同様に Collection インターフェイスを継承しているため、stream メソッドを呼び出して Stream API を利用することができます。
ArrayDeque クラスでの利用
キューは通常「入ってきた順番に1つずつ取り出して処理する(poll メソッドなど)」用途で使われますが、「現在キューに溜まっている未処理のタスクの情報を、元のキューの状態を変えずに一括で取得したり、加工したりしたい」といった要件が生じる場合があります。こういった「一括での読み取り・加工」では Stream API が威力を発揮します。
以下の例では、キューに溜まった「タスク名」を、すべて大文字に変換して結合した「残タスクの一覧」として表示します。
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.stream.Collectors;
public class ArrayDequeStreamSample {
public static void main(String[] args) {
// キュー(待ち行列)の準備
Deque<String> tasks = new ArrayDeque<>();
tasks.add("task-1");
tasks.add("task-2");
tasks.add("task-3");
// Streamを使って一括加工
String joinedTasks = tasks.stream()
.map(String::toUpperCase) // 各要素を大文字に変換 (map)
.collect(Collectors.joining(", ")); // カンマとスペースで結合 (joining)
System.out.println("未処理タスク一覧: [" + joinedTasks + "]");
}
}
実行結果:
未処理タスク一覧: [TASK-1, TASK-2, TASK-3]Map インターフェイスで Stream を利用する
HashMap クラスでの利用
HashMap など Map インターフェイスの実装クラスは Collection インターフェイスを継承していないため、List などのように直接的に Stream API を利用することはできません。ただし、Map はキーや値の集合を Set などの Collection として取得するメソッドを提供しているため、それらを経由して Stream API を利用することで、Map 内の要素を Stream で処理することができます。
特に、Map の entrySet メソッドで取得できる Map.Entry(マップのキーと値のペア)の Set を用いることで、キーと値の関係を維持したまま要素の取得や抽出などの操作が可能です。
以下の例では、「名前(キー)と点数(値)」のマップから「点数が80点以上」のメンバーを抽出し、Collectors.toMap メソッドを利用して新しい Map を生成しています。
public class HashMapStreamSample {
public static void main(String[] args) {
// Mapの準備(名前がキー、点数が値)
Map<String, Integer> scores = new HashMap<>();
scores.put("Tanaka", 85);
scores.put("Sato", 92);
scores.put("Suzuki", 70);
// entrySet() を取得して Stream を利用
Map<String, Integer> highScores = scores.entrySet().stream()
// 値が80(合格点)以上のエントリだけを抽出
.filter(entry -> entry.getValue() >= 80)
// 抽出したエントリから、新しいMapを構築
.collect(Collectors.toMap(
Map.Entry::getKey, // 新しいMapのキーには元のEntryのキー(名前)
Map.Entry::getValue // 新しいMapの値には元のEntryの値(点数)
));
System.out.println("元のMap: " + scores);
System.out.println("高得点者のMap: " + highScores);
}
}
実行結果:
元のMap: {Sato=92, Suzuki=70, Tanaka=85}
合格者のMap: {Sato=92, Tanaka=85}LinkedHashMap クラスでの利用
Collectors.toMap メソッドを利用する際、上記のサンプルのように型の指定をしない場合は、一般的に要素の順序を保持しない HashMap として作成されます。ソート順を維持したい場合は、Set のケースと同様に、具体的に生成するクラスとして要素の挿入順を維持する LinkedHashMap を指定することで、Map でも要素をソートして保持することができます。
以下の例では、点数(値)が高い順(降順)にソートして、各メンバーの名前と点数を新しい LinkedHashMap に詰め直します。生成する Map のクラスを指定する場合、Collectors.toMap メソッドには重複時のルールを引き渡せる点にも注目してください。
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;
public class LinkedHashMapStreamSample {
public static void main(String[] args) {
// HashMap のデータ準備
Map<String, Integer> scores = new HashMap<>();
scores.put("Tanaka", 85);
scores.put("Sato", 92);
scores.put("Suzuki", 70);
System.out.println("元のMap: " + scores);
// Streamを使って値(点数)の降順にソートし、LinkedHashMap に格納する
Map<String, Integer> sortedScores = scores.entrySet().stream()
// Map.Entryの機能を使って、値(Value)で降順ソート
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
// 新しいMapに詰め直す
.collect(Collectors.toMap(
Map.Entry::getKey, // キーの指定
Map.Entry::getValue, // 値の指定
(e1, e2) -> e1, // キーが重複した場合のルール(今回は重複しないので e1 をそのまま採用とする)
LinkedHashMap::new // 格納先のクラスを明示的に指定
));
System.out.println("ソートされたLinkedHashMap: " + sortedScores);
}
}
実行結果:
元のMap: {Sato=92, Suzuki=70, Tanaka=85}
ソートされたLinkedHashMap: {Sato=92, Tanaka=85, Suzuki=70}
いかがでしたでしょうか。List 以外のコレクションや Map を利用する際も「条件に合致したものだけ抽出して処理したい」などの要件がよく生じます。このようなケースでも、各コレクションの実装クラスのメソッドで個別に処理するのではなく Stream API の共通的な filter、sorted、collect といったメソッドを利用することで、ソースコードの可読性やメンテナンス性の向上につなげることができます。
次回の記事では、Stream API を用いて、これらのコレクションを別のコレクションの形式に変換して利用する例についてご紹介します。


