← Back to Home

Stream API

The Stream API (Java 8+) enables functional-style processing of collections and arrays. It allows you to transform, filter, aggregate, and process data declaratively with high readability and optional parallelism.

This is a very high-frequency interview topic and heavily used in modern Java applications.

What Is a Stream?

A stream is:

  • A sequence of elements
  • From a data source (Collection, Array, I/O)
  • Supporting functional operations
  • Not a data structure
  • Does not modify the source
list.stream();
          

Why Stream API Was Introduced

  • Reduce boilerplate code
  • Enable functional programming
  • Improve readability and maintainability
  • Support easy parallelism
  • Separate what from how

Stream Pipeline (Core Concept)

A stream operation follows this pipeline:

Source → Intermediate Operations → Terminal Operation
          

Example:

list.stream()
    .filter(x -> x > 10)
    .map(x -> x * 2)
    .forEach(System.out::println);
          

Characteristics of Streams

  • No storage – operates on source
  • Lazy evaluation – executes only on terminal operation
  • One-time use – cannot be reused
  • Functional – operations do not mutate source

Creating Streams

From Collection

Stream s = list.stream();
          

From Array

Stream s = Arrays.stream(arr);
          

Using Stream.of()

Stream s = Stream.of(1, 2, 3);
          

Intermediate Operations (Lazy)

Return a new Stream.

Common Intermediate Operations

Method Purpose
filter() Condition-based filtering
map() Transform elements
flatMap() Flatten nested streams
distinct() Remove duplicates
sorted() Sort elements
limit() Limit size
skip() Skip elements
peek() Debugging

filter()

list.stream()
    .filter(x -> x % 2 == 0)
    .forEach(System.out::println);
          

map()

list.stream()
    .map(String::toUpperCase)
    .forEach(System.out::println);
          

flatMap() (Interview Favorite)

List> data = List.of(List.of(1,2), List.of(3,4));
data.stream()
    .flatMap(List::stream)
    .forEach(System.out::println);
          

Converts nested structure into flat stream.

Terminal Operations (Trigger Execution)

Consume the stream and produce a result or side effect.

Common Terminal Operations

Method Result
forEach() Iteration
collect() Collection
reduce() Single value
count() Long
anyMatch() boolean
allMatch() boolean
noneMatch() boolean
findFirst() Optional
findAny() Optional

collect()

List even =
    list.stream()
        .filter(x -> x % 2 == 0)
        .collect(Collectors.toList());
          

reduce() (Interview Favorite)

int sum =
    list.stream()
        .reduce(0, Integer::sum);
          

Stream vs Collection (Interview Table)

Aspect Stream Collection
Storage ❌ No ✔ Yes
Iteration Internal External
Reusability ❌ No ✔ Yes
Laziness ✔ Yes ❌ No
Parallelism ✔ Easy ❌ Manual

Sequential vs Parallel Streams

Sequential (Default)

list.stream();
          

Parallel Stream

list.parallelStream();
          
  • Automatic multi-threading
  • Not always faster
  • Order may not be preserved

Stateless vs Stateful Operations

  • Stateless: map, filter (preferred)
  • Stateful: distinct, sorted (costly)

Optional with Streams

Optional max =
    list.stream().max(Integer::compareTo);
          

Avoids NullPointerException.

Common Beginner Mistakes

  • Modifying source inside stream
  • Reusing a stream
  • Using forEach() instead of map()
  • Overusing parallel streams
  • Writing complex logic in lambdas

Best Practices (Production-Grade)

  • Keep lambdas small and readable
  • Prefer method references
  • Use streams for data transformation, not business logic
  • Be cautious with parallel streams
  • Prefer Collectors for aggregation

Interview-Ready Answers

Short Answer

Stream API provides a functional way to process collections in Java.

Detailed Answer

In Java, the Stream API enables functional-style operations on sequences of elements. Streams support lazy evaluation, internal iteration, and can be processed sequentially or in parallel using intermediate and terminal operations without modifying the underlying data source.

Key Takeaway

Streams are about data processing, not data storage. They make Java code cleaner, declarative, and scalable, especially when combined with lambdas and functional interfaces.