Stream API の基本(stream(), filter, map, collect) — データ変換
Java 8 以降で導入された Stream API は「コレクションを宣言的に処理する」ための強力な仕組みです。
初心者がつまずきやすいポイントを、基本操作(stream → filter → map → collect) に絞って、例題とテンプレートで整理します。
基本の流れ
- stream()
- コレクションからストリームを生成。
- 例:
list.stream()
- filter(Predicate)
- 条件に合う要素だけ残す。
- 例:
.filter(x -> x > 10)
- map(Function)
- 要素を変換する。
- 例:
.map(String::length)
- collect(Collector)
- 結果をリストやセットなどにまとめる。
- 例:
.collect(Collectors.toList())
基本コード例
1) 数値リストから偶数だけ取り出す
import java.util.*;
import java.util.stream.*;
public class StreamBasic {
public static void main(String[] args) {
List<Integer> nums = List.of(1,2,3,4,5,6,7,8,9,10);
List<Integer> evens = nums.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
System.out.println(evens); // [2, 4, 6, 8, 10]
}
}
Java2) 文字列リストを大文字に変換
List<String> words = List.of("java", "stream", "api");
List<String> upper = words.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(upper); // [JAVA, STREAM, API]
Java3) オブジェクトから特定フィールドを抽出
class User {
String name; int age;
User(String n, int a) { name=n; age=a; }
}
List<User> users = List.of(new User("Alice",20), new User("Bob",30));
List<String> names = users.stream()
.map(u -> u.name)
.collect(Collectors.toList());
System.out.println(names); // [Alice, Bob]
Java例題で理解する
例題1: 成績リストから「合格者の名前」だけ抽出
class Student {
String name; int score;
Student(String n, int s) { name=n; score=s; }
}
List<Student> list = List.of(
new Student("Tanaka", 80),
new Student("Sato", 55),
new Student("Ito", 90)
);
List<String> passed = list.stream()
.filter(s -> s.score >= 60)
.map(s -> s.name)
.collect(Collectors.toList());
System.out.println(passed); // [Tanaka, Ito]
Java- ポイント: filter で条件抽出 → map でフィールド変換 → collect でリスト化。
例題2: 商品価格から「税込価格リスト」を作る
List<Integer> prices = List.of(100, 200, 300);
List<Integer> withTax = prices.stream()
.map(p -> (int)(p * 1.1))
.collect(Collectors.toList());
System.out.println(withTax); // [110, 220, 330]
Java- ポイント: map で計算処理を適用。
例題3: 文字列リストから「長さが3以上」のものを抽出
List<String> words = List.of("a","bb","ccc","dddd");
List<String> longWords = words.stream()
.filter(w -> w.length() >= 3)
.collect(Collectors.toList());
System.out.println(longWords); // [ccc, dddd]
Javaテンプレート集
- 基本形
list.stream()
.filter(x -> 条件)
.map(x -> 変換)
.collect(Collectors.toList());
Java- フィールド抽出
objects.stream()
.map(o -> o.field)
.collect(Collectors.toList());
Java- 条件付き抽出
list.stream()
.filter(x -> x > threshold)
.collect(Collectors.toList());
Java- 変換+集計
int sum = list.stream()
.mapToInt(x -> x.value)
.sum();
Java落とし穴と回避策
- 終端操作を忘れる: Stream は「collect」「forEach」など終端操作を呼ばないと実行されない。
- 副作用に頼りすぎ: map/filter 内で外部変数を書き換えるのは避ける。結果は collect でまとめる。
- 無限ストリームの有限化忘れ:
Stream.generateやiterateは limit/takeWhile を必ず入れる。 - sorted/distinct は全件読み込み: 大量データではメモリ負荷に注意。
まとめ
- stream() → filter → map → collect が基本パターン。
- filter は「選別」、map は「変換」、collect は「まとめ」。
- 宣言的に書けるので、コードが短く読みやすくなる。
- 実務では「条件抽出+フィールド変換+リスト化」が最もよく使われる組み合わせ。
👉 練習課題: 「社員リストから年齢30以上の人の名前を大文字にしてリスト化」してみると、filter・map・collect の流れが自然に身につきます。
