partitioningBy と counting
partitioningBy でストリームを2つのグループに分け、counting で要素数を数えます。
「partitioningBy と counting」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。
partitioningByの基本
Collectors.partitioningBy(predicate)は、ストリームをtrueとfalseという2つのグループに正確に分割し、Map<Boolean, List<T>>を返します。
import java.util.*;
import java.util.stream.*;
List<Integer> nums = List.of(1,2,3,4,5,6,7,8,9,10);
Map<Boolean, List<Integer>> evenOdd =
nums.stream().collect(Collectors.partitioningBy(n -> n % 2 == 0));
System.out.println(evenOdd.get(true)); // [2, 4, 6, 8, 10]
System.out.println(evenOdd.get(false)); // [1, 3, 5, 7, 9]partitioningByとfilterの違い
filterとは異なり、partitioningByは両方のグループを同時に保持します。分割後の両方を必要とする場合に便利です。
record Student(String name, int score) {}
List<Student> students = List.of(
new Student("Alice",90), new Student("Bob",55),
new Student("Carol",72), new Student("Dave",48)
);
Map<Boolean, List<Student>> result =
students.stream().collect(
Collectors.partitioningBy(s -> s.score() >= 60)
);
System.out.println("Passed: " + result.get(true).size());
System.out.println("Failed: " + result.get(false).size());partitioningByでの下流コレクター
groupingByと同じように、partitioningByと下流コレクターを組み合わせられます:
Map<Boolean, Long> passFailCount =
students.stream().collect(
Collectors.partitioningBy(
s -> s.score() >= 60,
Collectors.counting()
)
);
System.out.println("Passed: " + passFailCount.get(true));
System.out.println("Failed: " + passFailCount.get(false));counting()コレクター
Collectors.counting()は、ストリーム(または下流グループ)内の要素数を数えます。これはreducing(0L, e -> 1L, Long::sum)と同等の便利な方法です。
long count = Stream.of("a","bb","ccc","dddd")
.collect(Collectors.counting());
System.out.println(count); // 4
// Same as:
long count2 = Stream.of("a","bb","ccc","dddd").count();
// Use counting() as a downstream; use .count() as a terminal op下流コレクターとしてのcounting()
counting()は、groupingBy/partitioningByの下流コレクターとして使用すると特に便利です:
List<String> words = List.of("cat","dog","car","door","cup","dune");
Map<Character, Long> byFirstLetter =
words.stream().collect(
Collectors.groupingBy(w -> w.charAt(0), Collectors.counting())
);
byFirstLetter.forEach((c, n) -> System.out.println(c + ": " + n));
// c: 3, d: 3名前への分割
mappingを下流コレクターとして使用し、各分割から名前を取り出します:
Map<Boolean, List<String>> namesByPass =
students.stream().collect(
Collectors.partitioningBy(
s -> s.score() >= 60,
Collectors.mapping(Student::name, Collectors.toList())
)
);
System.out.println("Passed: " + namesByPass.get(true));
System.out.println("Failed: " + namesByPass.get(false));countingとsummarizingIntの組み合わせ
Collectors.summarizingInt()は、1回の走査で件数、合計、最小値、最大値、平均値を計算します:
IntSummaryStatistics stats =
students.stream().collect(
Collectors.summarizingInt(Student::score)
);
System.out.println("Count: " + stats.getCount());
System.out.println("Average: " + stats.getAverage());
System.out.println("Max: " + stats.getMax());
System.out.println("Min: " + stats.getMin());実践例: A/Bテストの分割
A/Bテストのために、ユーザーをコントロールグループと処置グループに分割します:
record User(String id, boolean isInTreatment) {}
List<User> users = List.of(
new User("u1",true), new User("u2",false),
new User("u3",true), new User("u4",false)
);
Map<Boolean, Long> split =
users.stream().collect(
Collectors.partitioningBy(User::isInTreatment, Collectors.counting())
);
System.out.println("Treatment: " + split.get(true)); // 2
System.out.println("Control: " + split.get(false)); // 2groupingBy + countingによる頻度Map
各要素の出現回数を数えます(単語頻度Map):
List<String> words2 = List.of("apple","banana","apple","cherry","banana","apple");
Map<String, Long> freq =
words2.stream().collect(
Collectors.groupingBy(w -> w, Collectors.counting())
);
freq.entrySet().stream()
.sorted(Map.Entry.<String,Long>comparingByValue().reversed())
.forEach(e -> System.out.println(e.getKey()+": "+e.getValue()));partitioningByは常に両方のキーを返す
groupingByとは異なり、partitioningByは一方のグループが空であっても、常にtrueとfalseの両方のキーを持つMapを返します。これにより、map.get(true)でNullPointerExceptionが発生するのを防げます。
List<Integer> allEven = List.of(2,4,6);
Map<Boolean, List<Integer>> m =
allEven.stream().collect(Collectors.partitioningBy(n -> n % 2 != 0));
System.out.println(m.get(true)); // [] (empty, not null)
System.out.println(m.get(false)); // [2, 4, 6]パフォーマンス: 1回の走査
partitioningByとcountingはどちらも、1回のストリーム走査で処理されます(O(n))。ソートは必要ありません。そのため、filterを2回呼び出したり、グループ化の前にソートしたりするよりも、はるかに効率的です。
理解度チェック
Collectors.partitioningBy(predicate)の戻り値の型は何ですか?
復習: partitioningByとcounting
重要なポイント:
- partitioningByは要素を2つのグループ(true/false)に正確に分割します
- 常に両方のキーが存在するため、groupingByと違ってNPEのリスクがありません
- counting()は要素数を数え、グループの下流コレクターとして使用できます
- summarizingInt/Long/Doubleは、1回の走査で件数+合計+最小値+最大値+平均値を計算します
- すべて1回のO(n)のストリーム走査で処理されます
よくある質問
「partitioningBy と counting」レッスンは無料ですか?
はい。「partitioningBy と counting」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「partitioningBy と counting」で何を学びますか?
partitioningBy でストリームを2つのグループに分け、counting で要素数を数えます。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「partitioningBy と counting」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- groupingBy:要素の分類
- partitioningBy と counting
- toMap、joining、summarizing
- カスタム Collector の作成