partitioningBy와 counting
partitioningBy로 스트림을 두 그룹으로 나누고 counting으로 요소 수를 셉니다.
partitioningBy와 counting은(는) CoddyKit의 무료 Java Academy 강의입니다. 이것은 4개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Java Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
partitioningBy 기본
Collectors.partitioningBy(predicate)는 stream을 정확히 두 그룹인 true와 false로 나누고 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()은 stream(또는 다운스트림 그룹)의 요소 수를 셉니다. 이는 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()는 한 번의 순회로 개수, 합계, 최솟값, 최댓값, 평균을 계산합니다:
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을 사용한 빈도 맵
각 요소의 등장 횟수를 셉니다(단어 빈도 맵):
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.get(true)에서 NullPointerExceptions가 발생하는 것을 방지할 수 있습니다.
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]성능: 한 번의 순회
partitioningBy와 counting은 모두 한 번의 stream 순회로 동작하므로 O(n)입니다. 정렬이 필요하지 않습니다. 따라서 filter를 두 번 호출하거나 그룹화 전에 정렬하는 것보다 훨씬 효율적입니다.
빠른 확인
Collectors.partitioningBy(predicate)의 반환 유형은 무엇입니까?
복습: partitioningBy와 counting
핵심 내용:
- partitioningBy는 정확히 두 그룹(true/false)으로 나눕니다
- 두 키가 항상 존재하므로 groupingBy와 달리 NPE가 발생할 위험이 없습니다
- counting()은 요소를 세며 그룹의 다운스트림 수집기로 사용할 수 있습니다
- summarizingInt/Long/Double은 한 번의 순회로 개수+합계+최솟값+최댓값+평균을 제공합니다
- 모두 한 번의 O(n) stream 순회로 동작합니다
자주 묻는 질문
“partitioningBy와 counting” 강의는 무료인가요?
네 — “partitioningBy와 counting” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Java Academy 강의 전체를 잠금 해제할 수 있습니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“partitioningBy와 counting”에서 뭘 배우나요?
partitioningBy로 스트림을 두 그룹으로 나누고 counting으로 요소 수를 셉니다. 브라우저에서 직접 실행하는 실습 코드로 Java Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Java Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Java Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 2번째 강의입니다.
“partitioningBy와 counting” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Java Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Java Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- groupingBy: 요소 분류
- partitioningBy와 counting
- toMap, joining, summarizing
- 사용자 정의 수집기 만들기