Stream<Order> s = orders.stream().filter(Order::paid);
long count = s.count();
List<Order> list = s.toList(); // IllegalStateException: stream has already been operated upon or closed스트림은 일회성 파이프라인입니다. 최종 연산이 끝나면 소비되어 다시 쓸 수 없습니다.
✅
List<Order> paid = orders.stream().filter(Order::paid).toList(); // 결과를 컬렉션으로 받아 재사용
long count = paid.size();
// 또는 Supplier<Stream<Order>> s = () -> orders.stream().filter(Order::paid); 로 매번 새로 생성toMap 에 merge 함수 없이 사용Map<String, Order> byCustomer = orders.stream().collect(toMap(Order::customer, o -> o));
// 같은 고객이 두 번 나오면 IllegalStateException: Duplicate key테스트 데이터에선 안 터지고 운영 데이터가 늘어나면 터지는 대표적 시한폭탄입니다.
✅
Map<String, Order> latest = orders.stream()
.collect(toMap(Order::customer, o -> o, (a, b) -> a.date().isAfter(b.date()) ? a : b));
// 또는 groupingBy 로 List 로 받기List<String> ids = new ArrayList<>();
orders.stream().filter(Order::paid).forEach(o -> ids.add(o.id())); // 순차에선 되지만 parallel 붙이면 깨짐스트림 람다는 무상태·비간섭이어야 합니다. forEach 로 외부 컬렉션을 채우는 것은 스트림을 for 문처럼 쓰는 것이고, 병렬화하는 순간 경쟁 조건이 됩니다.
✅
List<String> ids = orders.stream().filter(Order::paid).map(Order::id).toList();Files.lines 를 닫지 않음long errors = Files.lines(path).filter(l -> l.contains("ERROR")).count(); // 파일 핸들 누수Files.lines 는 파일을 열어둔 채 지연 읽기를 합니다. 스트림을 닫아야 파일이 닫힙니다. 배치에서 수천 파일을 처리하면 "Too many open files" 로 죽습니다.
✅
try (Stream<String> lines = Files.lines(path)) {
long errors = lines.filter(l -> l.contains("ERROR")).count();
}parallelStream()List<String> names = users.parallelStream().map(User::name).toList(); // 요소 50개, 작업은 getter 하나분할·합치기 비용이 작업보다 크면 순차보다 느립니다. 게다가 공용 풀을 공유하므로 서블릿 스레드 200개가 동시에 병렬 스트림을 쓰면 서로 기다립니다. 병렬은 측정 후, CPU 바운드 대량 데이터에만.
✅
List<String> names = users.stream().map(User::name).toList();
// 병렬이 필요하면: 데이터 수만 개 이상 + 요소당 계산 무거움 + I/O 없음 + 벤치마크로 확인peek 으로 로직 수행orders.stream().peek(o -> o.markProcessed()).count(); // JDK 9+ 에서 count 가 크기를 바로 알면 peek 이 실행 안 될 수 있음peek 은 디버깅 용도이며 실행이 보장되지 않습니다. 부수효과가 필요하면 forEach 를, 변환이면 map 을 쓰세요.
✅
orders.forEach(Order::markProcessed);Optional 반환 최종 연산에 .get() 바로 호출Order biggest = orders.stream().max(comparingLong(Order::amount)).get(); // 빈 리스트면 NoSuchElementException✅
Order biggest = orders.stream().max(comparingLong(Order::amount))
.orElseThrow(() -> new IllegalStateException("주문 없음"));