There are two types of stream operations: intermediate operations, which return another stream, and terminal operations, which return something other than a stream. Intermediate operations are lazy, meaning they aren’t actually executed until and unless a terminal stream operation is performed on their results. Consequently, if the result of an intermediate stream operation is not fed to a terminal operation, it serves no purpose, which is almost certainly an error.
This rule raises an issue when the result of an intermediate stream operation is not consumed by a terminal operation on all execution paths. Exception-handling paths are exempt.
widgets.stream().filter(b -> b.getColor() == RED); // Noncompliant
Stream<Widget> pipeline = widgets.stream().filter(b -> b.getColor() == RED); // Noncompliant; not consumed when widgets is empty
if (!widgets.isEmpty()) {
logger.info("Processing widgets");
pipeline.forEach(w -> logger.info("Widget: {}", w));
}
int sum = widgets.stream()
.filter(b -> b.getColor() == RED)
.mapToInt(b -> b.getWeight())
.sum();
Stream<Widget> pipeline = widgets.stream()
.filter(b -> b.getColor() == GREEN)
.mapToInt(b -> b.getWeight());
sum = pipeline.sum();
Reorder the code so that the stream is consumed on all paths:
if (!widgets.isEmpty()) {
logger.info("Processing widgets");
Stream<Widget> pipeline = widgets.stream().filter(b -> b.getColor() == RED); // Compliant; always consumed
pipeline.forEach(w -> logger.info("Widget: {}", w));
}