PECS principle
"Producer Extends, Consumer Super": use ? extends T when a collection only produces T values, and ? super T when it only consumes them:
void addDoubles(List<? extends Number> src) {
// src produces Numbers (producer)
}
void takeNumbers(List<? super Integer> dst) {
dst.add(5); // dst consumes Integers (consumer)
}
PECS keeps generics flexible while staying type-safe.
Stream pitfalls
Streams mutate nothing by themselves; terminal operations drive them. Avoid side effects in stream lambdas, they can run out of order in parallel streams. Prefer collect for aggregation and reserve forEach for terminal display only. Immutable collectors like toList return new collections rather than mutating inputs.