partitioningBy(true/false に分割) — 二分集計
Stream API の Collectors.partitioningBy は「条件に合うかどうか」で true/false の二分割を行う便利な集約方法です。
SQL の「WHERE 条件で2グループに分ける」イメージで、合格/不合格、偶数/奇数などの二分集計に向いています。
基本の仕組み
- partitioningBy(predicate):
- 条件を満たす要素は
trueグループ、満たさない要素はfalseグループに分類。 - 戻り値は
Map<Boolean, List<T>>。
- 条件を満たす要素は
- partitioningBy(predicate, downstreamCollector):
- true/false ごとにさらに集約(件数、合計、平均など)。
- 戻り値は
Map<Boolean, R>。
基本コード例
条件で二分割(偶数/奇数)
import java.util.*;
import java.util.stream.*;
public class PartitionBasic {
public static void main(String[] args) {
List<Integer> nums = List.of(1,2,3,4,5,6);
Map<Boolean, List<Integer>> partition =
nums.stream()
.collect(Collectors.partitioningBy(n -> n % 2 == 0));
System.out.println(partition);
// {false=[1, 3, 5], true=[2, 4, 6]}
}
}
Java件数を数える(downstream に counting)
List<Integer> nums = List.of(1,2,3,4,5,6);
Map<Boolean, Long> counts =
nums.stream()
.collect(Collectors.partitioningBy(n -> n % 2 == 0,
Collectors.counting()));
System.out.println(counts);
// {false=3, true=3}
Java合計値を出す(summingInt)
record Student(String name, int score) {}
List<Student> students = List.of(
new Student("Tanaka",80),
new Student("Sato",55),
new Student("Ito",90)
);
Map<Boolean, Integer> sumScores =
students.stream()
.collect(Collectors.partitioningBy(s -> s.score >= 60,
Collectors.summingInt(Student::score)));
System.out.println(sumScores);
// {false=55, true=170}
Java例題で理解する
例題1: 学生を「合格/不合格」に分ける
Map<Boolean, List<Student>> grouped =
students.stream()
.collect(Collectors.partitioningBy(s -> s.score >= 60));
System.out.println(grouped);
// {true=[Tanaka, Ito], false=[Sato]}
Java- ポイント: true が「合格」、false が「不合格」。
例題2: 商品を「高額/低額」に分けて件数集計
record Product(String name, int price) {}
List<Product> products = List.of(
new Product("A",100),
new Product("B",250),
new Product("C",160)
);
Map<Boolean, Long> counts =
products.stream()
.collect(Collectors.partitioningBy(p -> p.price >= 200,
Collectors.counting()));
System.out.println(counts);
// {false=2, true=1}
Java例題3: ログを「ERROR 含む/含まない」で分類
List<String> logs = List.of("INFO start","ERROR failed","WARN retry","ERROR timeout");
Map<Boolean, List<String>> partition =
logs.stream()
.collect(Collectors.partitioningBy(l -> l.contains("ERROR")));
System.out.println(partition);
// {false=[INFO start, WARN retry], true=[ERROR failed, ERROR timeout]}
Javaテンプレート集
- 基本二分割
Map<Boolean, List<T>> map =
stream.collect(Collectors.partitioningBy(x -> 条件));
Java- 件数集計
Map<Boolean, Long> map =
stream.collect(Collectors.partitioningBy(x -> 条件, Collectors.counting()));
Java- 合計集計
Map<Boolean, Integer> map =
stream.collect(Collectors.partitioningBy(x -> 条件, Collectors.summingInt(x -> 値)));
Java- 平均集計
Map<Boolean, Double> map =
stream.collect(Collectors.partitioningBy(x -> 条件, Collectors.averagingInt(x -> 値)));
Java落とし穴と回避策
- キーは必ず true/false: groupingBy と違ってキーは Boolean 固定。2分割しかできない。
- 大量データ: true/false 両方のリストを保持するため、メモリ負荷に注意。件数や合計だけ欲しいなら downstream Collector を使う。
- 条件の意味を明確に: true/false の意味が分かりにくい場合は、ラップして Enum や groupingBy を使う方が読みやすい。
まとめ
partitioningByは「条件に合うかどうか」で true/false に二分割する。- downstream Collector を組み合わせると件数・合計・平均などの二分集計が簡単。
- 合格/不合格、偶数/奇数、エラー/正常など、二値分類に最適。
👉 練習課題: 「社員リストを年齢30以上かどうかで partitioningBy し、各グループの人数を数える」コードを書いてみると、二分集計の便利さが体感できます。
