Filtering retains stream elements whose predicate returns true. In a Java Stream API pipeline, filter() is an intermediate operation: it records work, but processing begins only when a terminal operation runs. section 9.2
Avoid these narrowly scoped filtering mistakes:
- Do not use filter() predicates for unrelated mutations. A predicate that adds elements to another collection depends on call count and order, and may fail or lose data under parallelStream(). section 9.2
- Do not assume every terminal operation or collector accepts null values. Filter nulls early with filter(Objects::nonNull), or verify the specific operation in its documentation or JShell. section 9.4
- Use partitioningBy() when the goal is to retain both predicate outcomes instead of smuggling the rejected elements into a side-effect collection. section 9.2
Partition instead of mutating inside filter()
Avoid: list.stream().filter(str -> { if (str.contains("needle")) return true; containNoNeedle.add(str); return false; }).toList(); Prefer: Map<Boolean, List<String>> partitions = list.stream().collect(Collectors.partitioningBy(str -> str.contains("needle"))); section 9.2
Map<Boolean, List<String>> partitions = list.stream()
.collect(Collectors.partitioningBy(str -> str.contains("needle")));
List<String> containNoNeedle = partitions.get(false);
List<String> containNeedle = partitions.get(true);
Shows the canonical partitioningBy() arrangement for collecting matching and nonmatching elements. section 9.2
































