The Streams API, introduced in Java 8, provides a declarative way to process sequences of elements from a source such as a collection, array, or I/O channel. A stream pipeline consists of a source, zero or more intermediate operations, and exactly one terminal operation.
Key Points: • Intermediate operations (filter, map, sorted, distinct) are lazy — they build up a pipeline but do not execute until a terminal operation is invoked. • Terminal operations (collect, forEach, reduce, count) trigger execution and produce a result or side effect, consuming the stream in the process. • Streams do not store data; they compute on-demand from the underlying source and cannot be reused once consumed. • Streams can be sequential (stream()) or parallel (parallelStream()), letting the same pipeline scale across multiple cores with minimal code changes. • Because each operation returns a new stream, pipelines are built by fluently chaining method calls.
Example: list.stream().filter(x -> x > 5).map(x -> x * 2).collect(Collectors.toList()) reads as "take the list, keep values above 5, double them, and gather the results into a list" — nothing runs until collect() is called.
Code Example:
List<Integer> nums = Arrays.asList(1, 6, 3, 9, 2, 8);
List<Integer> result = nums.stream()
.filter(n -> n > 5)
.map(n -> n * 2)
.collect(Collectors.toList());
System.out.println(result); // [12, 18, 16]Interview Tip: A concise interview answer is:
"The Streams API lets you process a sequence of elements declaratively through a pipeline of a source, lazy intermediate operations like filter and map, and one terminal operation like collect or forEach that actually triggers execution. It supports both sequential and parallel execution with the same code, and streams themselves hold no data — they compute over the source on demand."