A side effect is behavior beyond an operation’s direct result: changing program state or performing work whose occurrence, order, or repetition matters. Keep result computation separate from such work where possible; the computation is then easier to test and reuse. section 3.1 section 9.2
Side effects make control flow significant. A malformed conditional chain can overwrite selected data before a final process(data) call. Computing data in one method and invoking process separately isolates the effect; using final locals can expose unintended reassignment. section 3.1
Avoid effects in Stream intermediate operations
Functions supplied to map() and filter() should normally derive their outcome only from return values. Adding rejected elements to another list inside filter() depends on exactly-once, ordered evaluation and can fail or lose data with parallelStream(). Use partitioningBy() when the goal is to split elements into two groups. section 9.2
List<String> containNoNeedle = new ArrayList<>();
List<String> containNeedle = list.stream()
.filter(str -> {
if (str.contains("needle")) {
return true;
}
containNoNeedle.add(str);
return false;
})
.toList();
This filter both classifies strings and mutates a second collection. The collector-based alternative produces both partitions without relying on intermediate-operation side effects. section 9.2
Do not place required work inside assert. Assertions may be disabled, so their expressions are not evaluated: set.add(value) may never run, and Matcher.find() may not populate groups needed afterward. Evaluate the operation first, then assert its result; use an explicit if for a failed precondition. section 10.1 section 10.8
Conditions should also avoid incidental updates. Non-short-circuit & and | evaluate both operands, which can intentionally run two update methods but obscures that intent and may be mistaken for a typo. Call the updates in separate statements, retain their boolean results, then combine those results with &&. section 2.7























