liveBook · Manning

Intermediate operation

As explained in 100 Java Mistakes and How to Avoid Them

An intermediate operation is a Java Stream pipeline operation that describes a transformation or selection and produces another stream for further processing.

An intermediate operation transforms or selects elements in a Java Stream pipeline and returns another stream. Typical operations include map(), filter(), skip(), limit(), and peek(). They build a deferred recipe: no stream processing starts until a terminal operation such as toList(), count(), collect(), or anyMatch() runs. section 9.2

Treat functions supplied to intermediate operations as free of important side effects. Stream processing may skip work, vary evaluation order, or run concurrently with parallelStream(); a lambda that mutates external state can therefore produce missing, reordered, duplicated, or unsafe results. peek() does not make mutation reliable. section 9.13 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 selects strings and appends rejected strings elsewhere. Its result now depends on how often and in what order the predicate runs. 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);

When both matching and nonmatching elements are needed, partitioningBy() expresses the two outputs without mutating a second collection during filtering. section 9.2

Intermediate operations also create a stream-ownership trap. Usually, an operation returns a new stream while marking the prior stream as consumed. If a stream variable is conditionally transformed but the returned stream is ignored, later terminal processing can fail with IllegalStateException. Reassign the variable, or encode the condition directly in the pipeline. section 9.3

Stream<String> stream = strings.stream();
if (skipHeader) {
  stream = stream.skip(1);    #1
}
List<String> trimmed = stream.map(String::trim).toList();

Reassigning stream after skip(1) preserves the pipeline that the terminal operation must consume. section 9.3

Use intermediate operations safely:

  • End the pipeline with one terminal operation; a stream cannot be consumed twice. section 9.13 section 9.3
  • Capture returned streams when adding conditional operations such as skip(). section 9.3
  • Collect to an intermediate collection or use a loop when later logic needs to traverse the same results again. section 9.3
  • Prefer a collector such as partitioningBy() when the apparent need for side effects is really a need for multiple result groups. section 9.2

Conditional skipping

Incorrect code calls stream.skip(1) and then continues with the original variable. Use stream = stream.skip(1), or write skip(skipHeader ? 1 : 0), before map(String::trim).toList(). The latter keeps the conditional behavior in one consumable pipeline. section 9.3

How 100 Java Mistakes and How to Avoid Them covers it

How deep it goes
Explains deferred execution, side-effect hazards, reassignment, and single-use failures, without detailing Stream internals.
Examples
Contrasts a mutating filter with partitioningBy(), and conditional skip code with reassignment or skip(0).
What it assumes
Assumes familiarity with Java Stream calls while defining the intermediate-to-terminal pipeline lifecycle.
What you can do after
Diagnose/debug with it by identifying unsafe side effects, discarded returned streams, and attempted stream reuse.
How it connects
Connects map(), filter(), skip(), limit(), peek(), terminal operations, parallelStream(), and Collectors.partitioningBy().

Also explained in

Compare how 3 books explain intermediate operation →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Java Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.