Java Stream API

Last Updated : 6 Apr 2026

Java Stream API allows you to process data in a functional style using streams. It provides a simple way to perform operations like filtering, mapping, and collecting data.

In this chapter, you will learn about the Java Stream API, its features, types of operations (intermediate, terminal, and short-circuit), methods, and various examples of using streams.

What is Java Stream API?

Stream API is a feature introduced in Java 8 under the java.util.stream package that allows you to process collections of data in a functional way. It does not store elements but processes them from a source through a pipeline of operations.

Stream provides the following features:

  • Stream does not store elements. It simply conveys elements from a source such as a data structure, an array, or an I/O channel through a pipeline of computational operations.
  • Stream is functional in nature. Operations performed on a stream do not modify its source. For example, filtering a stream obtained from a collection produces a new stream without the filtered elements, rather than removing elements from the source collection.
  • Stream is lazy and evaluates code only when required.
  • The elements of a stream are visited only once during the life of a stream. Like an Iterator, a new stream must be generated to revisit the same elements of the source.

We can use streams to filter, collect, print, and convert data from one data structure to another.

Core Operations on Java Streams

Java Streams support different types of operations that allow you to process and manipulate data efficiently.

1. Intermediate Operations

Intermediate operations in Java Streams return another Stream. They are typically used to transform or filter the elements of the original Stream. Since they are lazy, meaning they do not perform any processing until a terminal operation is called, multiple intermediate operations can be chained together.

Common Intermediate Operations:

  • map(Function<T, R>): Transforms each element of the Stream into another form using the provided function.
  • filter(Predicate<T>): Selects elements from the Stream based on a specified condition.
  • flatMap(Function<T, Stream<R>>): Transforms each element into zero or more elements by applying a function that returns a stream for each element.
  • distinct(): Removes duplicate elements from the Stream.
  • sorted(): Sorts the elements of the Stream.
  • limit(long n): Truncates the Stream to be no longer than the specified size.
  • skip(long n): Skips the first n elements of the Stream.
  • peek(Consumer<T>): Performs a specified action on each element of the Stream without consuming the elements.

2. Terminal Operations

Terminal operations are those operations that consume the Stream and produce a result, such as a value, a collection, or even a side effect. Once a terminal operation is invoked, the Stream is processed and cannot be reused.

Common Terminal Operations:

  • forEach(Consumer<T>): Acts as each element of the Stream.
  • collect(Collector<T, A, R>): Reduces the elements of the Stream into a mutable result container, such as a list or a map.
  • reduce(BinaryOperator<T>): Reduces the elements of the Stream to a single value using an associative accumulation function.
  • count(): Returns the count of elements in the Stream.
  • anyMatch(Predicate<T>): Returns true if any element of the Stream matches the given predicate.
  • allMatch(Predicate<T>): Returns true if all elements of the Stream match the given predicate.
  • noneMatch(Predicate<T>): Returns true if no elements of the Stream match the given predicate.
  • findFirst(): Returns an Optional describing the first element of the Stream, or an empty Optional if the Stream is empty.
  • findAny(): Returns an Optional describing some element of the Stream, or an empty Optional if the Stream is empty.

3. Short-Circuit Operations

Short-circuit operations are a subset of terminal operations that do not need to process the entire Stream to produce a result. They can provide an early exit from the stream processing pipeline, potentially saving computation time.

Common Short-Circuit Operations:

  • anyMatch(Predicate<T>): Stops processing and returns true if any element matches the given predicate.
  • allMatch(Predicate<T>): Stops processing and returns false if any element does not match the given predicate.
  • noneMatch(Predicate<T>): Stops processing and returns true if no elements match the given predicate.
  • findFirst(): Returns the first element encountered in the Stream and then stops processing.
  • findAny(): Returns any element encountered in the Stream and then stops processing.

Java Stream Interface Methods

Java Stream provides a wide range of methods that allow you to perform operations such as filtering, mapping, reducing, and collecting data.

The following table lists the commonly used Java Stream interface methods along with their descriptions:

MethodsDescription
boolean allMatch(Predicate<? super T> predicate)It returns all elements of this stream which match the provided predicate. If the stream is empty then true is returned and the predicate is not evaluated.
boolean anyMatch(Predicate<? super T> predicate)It returns any element of this stream that matches the provided predicate. If the stream is empty then false is returned and the predicate is not evaluated.
static <T> Stream.Builder<T> builder()It returns a builder for a Stream.
<R,A> R collect(Collector<? super T,A,R> collector)It performs a mutable reduction operation on the elements of this stream using a Collector. A Collector encapsulates the functions used as arguments to collect(Supplier, BiConsumer, BiConsumer), allowing for reuse of collection strategies and composition of collect operations such as multiple-level grouping or partitioning.
<R> R collect(Supplier<R> supplier, BiConsumer<R,? super T> accumulator, BiConsumer<R,R> combiner)It performs a mutable reduction operation on the elements of this stream. A mutable reduction is one in which the reduced value is a mutable result container, such as an ArrayList, and elements are incorporated by updating the state of the result rather than by replacing the result.
static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b)It creates a lazily concatenated stream whose elements are all the elements of the first stream followed by all the elements of the second stream. The resulting stream is ordered if both of the input streams are ordered, and parallel if either of the input streams is parallel. When the resulting stream is closed, the close handlers for both input streams are invoked.
long count()It returns the count of elements in this stream. This is a special case of a reduction.
Stream<T> distinct()It returns a stream consisting of the distinct elements (according to Object.equals(Object)) of this stream.
static <T> Stream<T> empty()It returns an empty sequential Stream.
Stream<T> filter(Predicate<? super T> predicate)It returns a stream consisting of the elements of this stream that match the given predicate.
Optional<T> findAny()It returns an Optional describing some element of the stream, or an empty Optional if the stream is empty.
Optional<T> findFirst()It returns an Optional describing the first element of this stream, or an empty Optional if the stream is empty. If the stream has no encounter order, then any element may be returned.
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)It returns a stream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element. Each mapped stream is closed after its contents have been placed into this stream. (If a mapped stream is null an empty stream is used, instead.)
DoubleStream flatMapToDouble(Function<? super T,? extends DoubleStream> mapper)It returns a DoubleStream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element. Each mapped stream is closed after its contents have placed been into this stream. (If a mapped stream is null an empty stream is used, instead.)
IntStream flatMapToInt(Function<? super T,? extends IntStream> mapper)It returns an IntStream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element. Each mapped stream is closed after its contents have been placed into this stream. (If a mapped stream is null an empty stream is used, instead.)
LongStream flatMapToLong(Function<? super T,? extends LongStream> mapper)It returns a LongStream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element. Each mapped stream is closed after its contents have been placed into this stream. (If a mapped stream is null an empty stream is used, instead.)
void forEach(Consumer<? super T> action)It performs an action for each element of this stream.
void forEachOrdered(Consumer<? super T> action)It performs an action for each element of this stream, in the encounter order of the stream if the stream has a defined encounter order.
static <T> Stream<T> generate(Supplier<T> s)It returns an infinite sequential unordered stream where each element is generated by the provided Supplier. This is suitable for generating constant streams, streams of random elements, etc.
static <T> Stream<T> iterate(T seed,UnaryOperator<T> f)It returns an infinite sequential ordered Stream produced by iterative application of a function f to an initial element seed, producing a Stream consisting of seed, f(seed), f(f(seed)), etc.
Stream<T> limit(long maxSize)It returns a stream consisting of the elements of this stream, truncated to be no longer than maxSize in length.
<R> Stream<R> map(Function<? super T,? extends R> mapper)It returns a stream consisting of the results of applying the given function to the elements of this stream.
DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper)It returns a DoubleStream consisting of the results of applying the given function to the elements of this stream.
IntStream mapToInt(ToIntFunction<? super T> mapper)It returns an IntStream consisting of the results of applying the given function to the elements of this stream.
LongStream mapToLong(ToLongFunction<? super T> mapper)It returns a LongStream consisting of the results of applying the given function to the elements of this stream.
Optional<T> max(Comparator<? super T> comparator)It returns the maximum element of this stream according to the provided Comparator. This is a special case of a reduction.
Optional<T> min(Comparator<? super T> comparator)It returns the minimum element of this stream according to the provided Comparator. This is a special case of a reduction.
boolean noneMatch(Predicate<? super T> predicate)It returns elements of this stream match the provided predicate. If the stream is empty then true is returned and the predicate is not evaluated.
@SafeVarargs static <T> Stream<T> of(T... values)It returns a sequential ordered stream whose elements are the specified values.
static <T> Stream<T> of(T t)It returns a sequential Stream containing a single element.
Stream<T> peek(Consumer<? super T> action)It returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.
Optional<T> reduce(BinaryOperator<T> accumulator)It performs a reduction on the elements of this stream, using an associative accumulation function, and returns an Optional describing the reduced value, if any.
T reduce(T identity, BinaryOperator<T> accumulator)It performs a reduction on the elements of this stream, using the provided identity value and an associative accumulation function, and returns the reduced value.
<U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)It performs a reduction on the elements of this stream, using the provided identity, accumulation and combining functions.
Stream<T> skip(long n)It returns a stream consisting of the remaining elements of this stream after discarding the first n elements of the stream. If this stream contains fewer than n elements then an empty stream will be returned.
Stream<T> sorted()It returns a stream consisting of the elements of this stream, sorted according to natural order. If the elements of this stream are not Comparable, a java.lang.ClassCastException may be thrown when the terminal operation is executed.
Stream<T> sorted(Comparator<? super T> comparator)It returns a stream consisting of the elements of this stream, sorted according to the provided Comparator.
Object[] toArray()It returns an array containing the elements of this stream.
<A> A[] toArray(IntFunction<A[]> generator)It returns an array containing the elements of this stream, using the provided generator function to allocate the returned array, as well as any additional arrays that might be required for a partitioned execution or for resizing.

Examples of Java Stream API

Let's understand Java Stream API with the help of some important examples.

Example 1: Filtering Collection without Using Stream

In the following example, we are filtering data without using stream. This approach we are used before the stream package was released.

Compile and Run

Output:

[25000.0, 28000.0, 28000.0]

Example 2: Filtering Collection Using Stream

In this example, data is filtered using the stream() method, making the code more simple and efficient.

Compile and Run

Output:

[90000.0]

Example 3: Iterating Using Stream

We can use stream to iterate any number of times. Stream provides predefined methods to deal with the logic we implement. In the following example, we are iterating, filtering and passed a limit to fix the iteration.

Compile and Run

Output:

5
10
15
20
25

Example 4: Using reduce() Method

This method takes a sequence of input elements and combines them into a single summary result by repeated operation. For example, finding the sum of numbers, or accumulating elements into a list. In this example, we are using the reduce() method to calculate the total sum of product prices.

Compile and Run

Output:

201000.0
201000.0

Example 5: Finding Max and Min Values Using Stream

We can also use collectors to compute sum of numeric values. In the following example, we are using Collectors class and it's specified methods to compute sum of all the product prices.

Compile and Run

Output:

90000.0
25000.0

Java Stream Specializations

The Java Streams API offers specialized stream types for handling primitive data types: IntStream for integers, LongStream for long integers, and DoubleStream for doubles. These specializations provide better performance and include additional operations tailored for numerical computations, making them suitable for working with primitive data.

1. Specialized Operations

Specialized streams provide operations that are particularly useful when working with numeric data. These operations extend beyond those available in the generic Stream<T> interface and offer methods that support arithmetic computations directly on streams of primitive values.

2. Reduction Operations

Reduction operations are a type of terminal operation that combines all elements of a stream into a single result. These operations use a binary operator to repeatedly apply a function, carrying forward the result as the first argument for the next operation. This approach is useful for summarizing or aggregating numerical data.

Java Stream: File Operations

Java Streams API, introduced in Java 8, provides an efficient and expressive way to handle streams of data, including files. In this context, the term "streams" refers to a sequence of elements supporting sequential and parallel aggregate operations, and should not be confused with InputStream and OutputStream from I/O streams.

Using the Streams API to manipulate file data involves reading from files, processing the data line by line or in bulk, and often writing results to another file. This is achieved using the Files class in the java.nio.file package, which integrates seamlessly with the Streams API.

Example 1: Reading and Processing File Data

In this example, file data is read line by line, filtered based on length, and converted to uppercase.

Input:

Output:

Read line: hello
Read line: world
Read line: Yes
Read line: 12345
Read line: Spaces
Read line: Java!
Read line: 1234
Read line: ABCDE
Filtered strings with length 5 (converted to uppercase): [HELLO, WORLD, 12345, JAVA!, ABCDE]

Example 2: Writing Data to a File Using Stream

In this example, data is written to a file using the Stream API.

Output:

Text has been successfully written to the file.

Java 8 Stream