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.
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:
We can use streams to filter, collect, print, and convert data from one data structure to another.
Java Streams support different types of operations that allow you to process and manipulate data efficiently.
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:
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:
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:
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:
| Methods | Description |
|---|---|
| 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. |
Let's understand Java Stream API with the help of some important examples.
In the following example, we are filtering data without using stream. This approach we are used before the stream package was released.
Output:
[25000.0, 28000.0, 28000.0]
In this example, data is filtered using the stream() method, making the code more simple and efficient.
Output:
[90000.0]
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.
Output:
5 10 15 20 25
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.
Output:
201000.0 201000.0
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.
Output:
90000.0 25000.0
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.
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.
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 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.
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]
In this example, data is written to a file using the Stream API.
Output:
Text has been successfully written to the file.

We request you to subscribe our newsletter for upcoming updates.