Fundamentals 25 min read

Java Stream API Tutorial: Definitions, Operations, and Code Examples

This tutorial provides a comprehensive overview of Java's Stream API, explaining its definition, how to obtain streams, the structure of stream processing, and detailed examples of common intermediate and terminal operations with complete code snippets.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Java Stream API Tutorial: Definitions, Operations, and Code Examples

This article is a detailed tutorial on Java's Stream API, covering its definition, how to obtain streams, the composition of stream processing, and a thorough list of common intermediate and terminal operations with code examples.

Definition of Stream

In Java, a Stream is a component that can internally iterate over its elements, meaning the Stream handles the iteration itself. This differs from using a Collection's iterator or the Iterable interface's forEach method, where the developer must manage iteration.

Stream Processing

Processor methods (or listeners) can be attached to a Stream. When the Stream iterates internally, each element is passed to these processors, which are invoked for every element, forming a processing chain.

Multiple processor methods can be chained: the output of one processor becomes the input for the next. Processors may return the same element or a transformed one, depending on their purpose.

How to Obtain a Stream

The most common way to get a Stream is from a Collection. Example:

List<String> items = new ArrayList<>();
items.add("one");
items.add("two");
items.add("three");
Stream<String> stream = items.stream();

All collection objects implement the Collection interface, which defines the stream() method.

Composition of Stream Processing

A Stream processing pipeline consists of a source, zero or more intermediate operations, and a terminal operation.

Source: the origin of elements, such as a Collection.

Intermediate operations: added processors that return a new Stream; they are lazily executed.

Terminal operation: triggers internal iteration, applies all processors, and returns a result.

Intermediate Operations

map

map()

transforms each element to another object, e.g., converting strings to uppercase.

List<String> list = new ArrayList<>();
Stream<String> stream = list.stream();
Stream<String> streamMapped = stream.map(value -> value.toUpperCase());

filter

filter()

removes elements that do not satisfy a given Predicate.

Stream<String> longStringsStream = stream.filter(value -> value.length() >= 3);

flatMap

flatMap()

maps each element to a Stream and then flattens the resulting Streams into a single Stream.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamFlatMapExamples {
    public static void main(String[] args) {
        List<String> stringList = new ArrayList<>();
        stringList.add("One flew over the cuckoo's nest");
        stringList.add("To kill a mockingbird");
        stringList.add("Gone with the wind");
        Stream<String> stream = stringList.stream();
        stream.flatMap(value -> {
            String[] split = value.split(" ");
            return Arrays.asList(split).stream();
        }).forEach(value -> System.out.println(value));
    }
}

distinct

distinct()

returns a new Stream containing only unique elements, removing duplicates.

List<String> stringList = new ArrayList<>();
stringList.add("one");
stringList.add("two");
stringList.add("three");
stringList.add("one");
Stream<String> stream = stringList.stream();
List<String> distinctStrings = stream.distinct().collect(Collectors.toList());
System.out.println(distinctStrings); // [one, two, three]

limit

limit(n)

truncates the Stream to contain at most n elements.

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;

public class StreamLimitExample {
    public static void main(String[] args) {
        List<String> stringList = new ArrayList<>();
        stringList.add("one");
        stringList.add("two");
        stringList.add("three");
        stringList.add("one");
        Stream<String> stream = stringList.stream();
        stream.limit(2).forEach(element -> System.out.println(element));
    }
}

peek

peek()

is a debugging intermediate operation that consumes each element with a Consumer without modifying the Stream.

Stream.of("one", "two", "three", "four")
    .filter(e -> e.length() > 3)
    .peek(e -> System.out.println("Filtered value: " + e))
    .map(String::toUpperCase)
    .peek(e -> System.out.println("Mapped value: " + e))
    .collect(Collectors.toList());

Terminal Operations

Terminal operations start internal iteration and produce a final result.

anyMatch

anyMatch(predicate)

returns true if any element satisfies the predicate.

boolean anyMatch = stream.anyMatch(value -> value.startsWith("One"));
System.out.println(anyMatch);

allMatch

allMatch(predicate)

returns true only if all elements satisfy the predicate.

boolean allMatch = stream.allMatch(value -> value.startsWith("One"));
System.out.println(allMatch);

noneMatch

noneMatch(predicate)

returns true if no elements satisfy the predicate.

boolean noneMatch = stream.noneMatch(element -> "xyz".equals(element));
System.out.println("noneMatch = " + noneMatch);

collect

collect()

gathers the Stream's elements into a collection or another container.

List<String> stringsAsUppercaseList = stream
    .map(value -> value.toUpperCase())
    .collect(Collectors.toList());
System.out.println(stringsAsUppercaseList);

count

count()

returns the number of elements in the Stream.

long count = stream.flatMap(value -> {
    String[] split = value.split(" ");
    return Arrays.asList(split).stream();
}).count();
System.out.println("count = " + count);

findAny

findAny()

returns an Optional containing any element of the Stream.

Optional<String> anyElement = stream.findAny();
if (anyElement.isPresent()) {
    System.out.println(anyElement.get());
} else {
    System.out.println("not found");
}

findFirst

findFirst()

returns an Optional containing the first element of the Stream.

Optional<String> firstElement = stream.findFirst();
if (firstElement.isPresent()) {
    System.out.println(firstElement.get());
} else {
    System.out.println("not found");
}

forEach

forEach()

performs an action for each element; it returns void.

stream.forEach(System.out::println);

min / max

min(comparator)

and max(comparator) return the smallest or largest element according to the provided Comparator, wrapped in an Optional.

Optional<String> min = stream.min(String::compareTo);
Optional<String> max = stream.max(String::compareTo);

reduce

reduce()

aggregates Stream elements into a single result using a binary operator.

Optional<String> reduced = stream.reduce((value, combined) -> combined + " + " + value);
reduced.ifPresent(System.out::println);

toArray

toArray()

converts the Stream into an array of Object, with an overloaded version allowing a typed array.

Object[] objects = stream.toArray();
String[] strArray = stream.toArray(String[]::new);

Stream Concatenation

The static method Stream.concat(stream1, stream2) merges two Streams into one.

Stream<String> concatStream = Stream.concat(stream1, stream2);
List<String> combined = concatStream.collect(Collectors.toList());
System.out.println(combined);

Creating Streams from Arrays

The static method Stream.of(...) can create a Stream from individual objects, multiple objects, or an array.

Stream<String> stream1 = Stream.of("one", "two", "three");
Stream<String> stream2 = Stream.of(new String[]{"one", "two"});
System.out.println(stream1.count()); // 3
System.out.println(stream2.count()); // 2

In summary, this article enumerates the main intermediate and terminal operations of Java Streams, providing simple examples to illustrate their effects. A follow‑up article will demonstrate more complex, high‑frequency Stream usages in real projects.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaLambdafunctional programmingCode ExamplesStream APIIntermediate OperationsTerminal Operations
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.