Skip to content

Learn and practice Java Stream API through detailed explanations, practical examples, and logical problems commonly asked in interviews.

Notifications You must be signed in to change notification settings

techprakashverma/java-stream-api

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Java Stream API – Complete Overview

Java Stream Overview

What is Stream<T>?

  • Stream<T> represents a sequence of elements supporting functional-style operations.
  • It extends BaseStream<T, Stream<T>>.
  • Streams enable declarative, lazy, and efficient processing of collections and other data sources.
  • Streams do not store data; they process data from a source (Collection, Array, I/O, etc.).

1. Stream Method Classification

Category Description
Stream Creation Static or default methods to create streams
Intermediate Operations Lazy operations that return a new Stream (support chaining)
Terminal Operations Trigger stream execution and produce results or side-effects
Short-Circuiting Operations that may stop processing early
Parallel / Sequential Control execution mode
Close & Resource Cleanup and resource handling

2. Stream Creation Methods

Method Example Description
Stream.of(T...) Stream.of(1, 2, 3) Create stream from values
Stream.empty() Stream.empty() Create an empty stream
Stream.generate(Supplier) Stream.generate(() -> rand.nextInt(100)).limit(5) Infinite lazy stream
Stream.iterate(seed, f) Stream.iterate(1, n -> n + 2).limit(5) Infinite iterative stream
Stream.iterate(seed, predicate, f) (Java 9+) Stream.iterate(1, n -> n <= 10, n -> n + 1) Bounded iteration

3. Intermediate Operations (Lazy)

These operations return a new Stream and are executed only when a terminal operation is invoked.

  • filter(Predicate<T>) – Filter elements
  • map(Function<T,R>) – Transform elements
  • flatMap(Function<T,Stream<R>>) – Flatten nested streams
  • distinct() – Remove duplicates
  • sorted() / sorted(Comparator) – Sort elements
  • peek(Consumer) – Debug elements without consuming
  • limit(long) – Keep first N elements
  • skip(long) – Skip first N elements
  • takeWhile(Predicate) (Java 9+) – Take elements while condition holds
  • dropWhile(Predicate) (Java 9+) – Drop elements while condition holds
  • unordered() – Remove ordering constraints

4. Terminal Operations (Trigger Processing)

Terminal operations consume the stream and produce a result or side-effect.

  • forEach(Consumer) – Process each element
  • forEachOrdered(Consumer) – Ordered processing (parallel streams)
  • toArray() / toArray(IntFunction) – Convert to array
  • reduce() – Reduce elements to a single value
  • collect(Collector) – Mutable reduction (e.g., toList)
  • min(Comparator) / max(Comparator) – Find min/max
  • count() – Count elements
  • anyMatch(Predicate) – Match any element
  • allMatch(Predicate) – Match all elements
  • noneMatch(Predicate) – Match none
  • findFirst() – Find first element
  • findAny() – Find any element (parallel-friendly)

5. Short-Circuiting Operations

These operations may terminate stream processing early.

Operation Type
anyMatch Terminal
allMatch Terminal
noneMatch Terminal
findFirst Terminal
findAny Terminal
limit Intermediate
takeWhile Intermediate

6. Parallel & Sequential Control

Method Description
parallel() Enable parallel execution
sequential() Switch back to sequential
isParallel() Check execution mode

7. Resource & Close Handling

Method Usage
close() Close stream and release resources
onClose(Runnable) Register cleanup handler

8. BaseStream Methods (Inherited)

  • iterator()
  • spliterator()
  • unordered()
  • parallel()
  • sequential()
  • isParallel()
  • onClose()
  • close()

9. Interview-Ready One-Liner Summary

Java Streams provide a pipeline of operations classified into creation, intermediate (lazy), and terminal (eager). Stream processing occurs only after a terminal operation is invoked, enabling efficient, declarative, and parallel data processing with short-circuiting support.


10. Key Points to Remember

  • Streams are single-use
  • Streams are lazy
  • No modification of original data
  • Prefer streams for readability and functional style
  • Avoid heavy logic in peek()

Difference Between Intermediate and Terminal Operations in Java Streams

Java Stream operations are broadly classified into Intermediate and Terminal operations based on when they execute, what they return, and how they affect the stream lifecycle.

Understanding this difference is critical for:

  • Correct Stream usage
  • Writing efficient code
  • Clearing Java interview questions confidently

1. Intermediate Operations

Definition

Intermediate operations are operations that:

  • Transform a stream into another stream
  • Are lazy in nature
  • Do not trigger execution on their own

They are mainly used to build the stream pipeline.


Key Characteristics

  • ✅ Return a Stream<T>
  • ✅ Can be chained
  • ✅ Executed only when a terminal operation is called
  • ✅ Do not consume the stream
  • ✅ Support lazy evaluation
  • ❌ Do not produce a final result

Why Are They Lazy?

Intermediate operations are recorded, not executed immediately.

The JVM waits until a terminal operation is encountered and then processes elements only as required.

This improves:

  • ⚡ Performance
  • 💾 Memory efficiency
  • ⏹ Short-circuiting behavior

Example (No Execution Happens)

Stream<Integer> stream =
    numbers.stream()
           .filter(n -> {
               System.out.println("filter: " + n);
               return n > 10;
           })
           .map(n -> {
               System.out.println("map: " + n);
               return n * 2;
           });

Nothing is printed because there is no terminal operation.


Common Intermediate Operations

Intermediate operations are lazy, return a Stream, and are used to build the processing pipeline.

Operation Purpose
filter() Select elements based on condition
map() Transform elements
flatMap() Flatten nested streams
distinct() Remove duplicates
sorted() Sort elements
peek() Debug stream elements
limit() Restrict number of elements
skip() Skip elements
takeWhile() (Java 9+) Take elements while condition holds
dropWhile() (Java 9+) Drop elements while condition holds
unordered() Remove encounter order

2. Terminal Operations

Definition

Terminal operations are operations that:

  • ✅ Trigger execution of the stream pipeline
  • ✅ Produce a final result or side-effect
  • ✅ Close the stream

⚠️ Once a terminal operation is executed, the stream cannot be reused.


Key Characteristics

  • ❌ Do not return a Stream
  • ✅ Trigger processing of all intermediate operations
  • ✅ Consume the stream
  • ❌ Cannot be chained further
  • ❌ Stream becomes invalid after execution

Example (Execution Happens)

List<Integer> result =
    numbers.stream()
           .filter(n -> {
               System.out.println("filter: " + n);
               return n > 10;
           })
           .map(n -> {
               System.out.println("map: " + n);
               return n * 2;
           })
           .collect(Collectors.toList());

Execution now happens element by element.

Common Terminal Operations

Terminal operations trigger execution of the stream pipeline and consume the stream.

Operation Result Type
forEach() void
forEachOrdered() void
collect() Collection / Map
reduce() Single value
toArray() Array
count() long
min() / max() Optional
anyMatch() boolean
allMatch() boolean
noneMatch() boolean
findFirst() Optional
findAny() Optional

Lazy vs Eager Execution (Very Important)

Lazy Execution (Intermediate Operations)

  • Not executed immediately
  • Stored internally as pipeline steps
  • Execution starts only after a terminal operation is called

Eager Execution (Terminal Operations)

  • Executes immediately
  • Pulls data from the source
  • Applies intermediate operations per element
  • Produces the final result

Element-by-Element Processing (Internal Working)

Streams do not process all elements at once.

Processing flow:

  1. One element is pulled from the source
  2. Passed through all intermediate operations
  3. Consumed by the terminal operation
  4. Repeats for the next element

This design enables short-circuiting.


Short-Circuiting Example

numbers.stream()
       .filter(n -> n > 10)
       .findFirst();

Stops processing as soon as the first matching element is found.

Comparison Table (Interview Favorite)

Feature Intermediate Operation Terminal Operation
Return Type Stream Value / Collection / Optional / void
Execution Lazy Eager
Triggers Processing No Yes
Stream Reusability Stream continues Stream is closed
Chaining Allowed Not allowed
Position in Pipeline Middle End
Performance Impact Optimized via laziness Executes full or partial pipeline

End-to-End Example

int sum =
    numbers.stream()               // Stream creation
           .filter(n -> n > 10)    // Intermediate
           .map(n -> n * 2)        // Intermediate
           .limit(3)               // Intermediate (short-circuit)
           .reduce(0, Integer::sum); // Terminal

Without the terminal operation, nothing executes.

Common Interview Questions

Can a stream have multiple terminal operations?
No. A stream can have only one terminal operation.

Can we reuse a stream after a terminal operation?
No. It throws IllegalStateException.

Why is peek() an intermediate operation?
Because it returns a Stream and does not consume it.

Why is laziness important in Streams?
It improves performance, enables short-circuiting, and reduces memory usage.


Interview One-Liner Summary

Intermediate operations build a lazy processing pipeline and return streams, whereas terminal operations trigger execution, consume the stream, and produce the final result.


Recommended for Interview Preparation

  • Stream vs Collection
  • map() vs flatMap()
  • findFirst() vs findAny()
  • Parallel stream pitfalls
  • Short-circuiting behavior

Happy Coding 🚀

About

Learn and practice Java Stream API through detailed explanations, practical examples, and logical problems commonly asked in interviews.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages