Backend Development 23 min read

Java Stream API Overview and Practical Usage Examples

This article provides a comprehensive guide to Java 8 Stream API, covering its core characteristics, creation methods, essential interfaces, and common operations such as filtering, mapping, reducing, collecting, grouping, and sorting, with clear code examples for each concept.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Java Stream API Overview and Practical Usage Examples

1. Basic Characteristics

Java 8 introduced the Stream API, which treats collections or arrays as a flow of elements that can be filtered, sorted, and processed without storing intermediate results.

1.1 Stream Features

stream does not store data; it computes results on demand.

stream does not modify the source; it typically produces a new collection.

stream operations are lazy and execute only when a terminal operation is invoked.

Streams are single‑use; invoking a terminal operation on a consumed stream throws an exception.

1.2 Creating Streams

From arrays:

public static void main(String[] args) {
    // 1. Arrays.stream for primitive types
    int[] arr = new int[]{1,2,34,5};
    IntStream intStream = Arrays.stream(arr);
    // 2. Arrays.stream for reference types
    Student[] studentArr = new Student[]{new Student("s1",29), new Student("s2",27)};
    Stream
studentStream = Arrays.stream(studentArr);
    // 3. Stream.of for var‑args
    Stream
stream1 = Stream.of(1,2,34,5,65);
    // 4. Stream.of for array streams (produces Stream
)
    Stream
stream2 = Stream.of(arr, arr);
    stream2.forEach(System.out::println);
}

From collections:

public static void main(String[] args) {
    List
strs = Arrays.asList("11212","dfd","2323","dfhgf");
    // ordinary stream
    Stream
stream = strs.stream();
    // parallel stream
    Stream
stream1 = strs.parallelStream();
}

2. Stream API Details

The BaseStream interface defines the fundamental operations for all streams.

public interface BaseStream
> extends AutoCloseable {
    Iterator
iterator();
    Spliterator
spliterator();
    boolean isParallel();
    S sequential();
    S parallel();
    S unordered();
    S onClose(Runnable closeHandler);
    @Override void close();
}

The Stream interface extends BaseStream and adds a rich set of intermediate and terminal operations.

public interface Stream
extends BaseStream
> {
    Stream
filter(Predicate
predicate);
Stream
map(Function
mapper);
    IntStream mapToInt(ToIntFunction
mapper);
    LongStream mapToLong(ToLongFunction
mapper);
    DoubleStream mapToDouble(ToDoubleFunction
mapper);
Stream
flatMap(Function
> mapper);
    Stream
distinct();
    Stream
sorted();
    Stream
sorted(Comparator
comparator);
    Stream
peek(Consumer
action);
    Stream
limit(long maxSize);
    Stream
skip(long n);
    void forEach(Consumer
action);
    void forEachOrdered(Consumer
action);
    Object[] toArray();
A[] toArray(IntFunction
generator);
    T reduce(T identity, BinaryOperator
accumulator);
    Optional
reduce(BinaryOperator
accumulator);
U reduce(U identity, BiFunction
accumulator, BinaryOperator
combiner);
R collect(Supplier
supplier, BiConsumer
accumulator, BiConsumer
combiner);
R collect(Collector
collector);
    Optional
min(Comparator
comparator);
    Optional
max(Comparator
comparator);
    long count();
    boolean anyMatch(Predicate
predicate);
    boolean allMatch(Predicate
predicate);
    boolean noneMatch(Predicate
predicate);
    Optional
findFirst();
    Optional
findAny();
    static
Builder
builder() { return new Streams.StreamBuilderImpl<>(); }
    static
Stream
empty() { return StreamSupport.stream(Spliterators.emptySpliterator(), false); }
    static
Stream
of(T t) { return StreamSupport.stream(new Streams.StreamBuilderImpl<>(t), false); }
    @SafeVarargs static
Stream
of(T... values) { return Arrays.stream(values); }
    static
Stream
iterate(final T seed, final UnaryOperator
f) { /* implementation omitted */ }
    static
Stream
generate(Supplier
s) { /* implementation omitted */ }
    static
Stream
concat(Stream
a, Stream
b) { /* implementation omitted */ }
}

2.1 Common Operations

Filtering and Matching

List
intList = Arrays.asList(6,7,3,8,1,2,9);
List
collect = intList.stream().filter(x -> x > 7).collect(Collectors.toList());
System.out.println(collect); // [8,9]

List
collect2 = personList.stream().filter(p -> p.getSalary() > 8000).collect(Collectors.toList());

Optional
findFirst = list.stream().filter(x -> x > 6).findFirst();
Optional
findAny = list.parallelStream().filter(x -> x > 6).findAny();
boolean anyMatch = list.stream().anyMatch(x -> x < 6);

Aggregation (max, min, count)

Optional
max = list.stream().max(Comparator.comparing(String::length));
Optional
maxInt = list.stream().max(Comparator.naturalOrder());
Optional
maxPerson = list.stream().max(Comparator.comparingInt(Person::getSalary));
long count = list.stream().filter(x -> x > 6).count();

Reduction (reduce)

Integer sum = list.stream().reduce(1, (x, y) -> x + y);
Optional
maxOpt = list.stream().reduce(Integer::max);
Integer sumSalary = personList.stream().reduce(0, (sum, p) -> sum + p.getSalary(), Integer::sum);

Collecting (collect)

Double avgSalary = personList.stream().collect(Collectors.averagingDouble(Person::getSalary));
DoubleSummaryStatistics stats = personList.stream().collect(Collectors.summarizingDouble(Person::getSalary));
String names = personList.stream().map(Person::getName).collect(Collectors.joining(","));
List
nameList = personList.stream().map(Person::getName).collect(Collectors.toList());
Set
nameSet = personList.stream().map(Person::getName).collect(Collectors.toSet());
Map
personMap = personList.stream().collect(Collectors.toMap(Person::getName, p -> p));
Map
> groupByName = personList.stream().collect(Collectors.groupingBy(Person::getName));
Map
>> multiGroup = personList.stream().collect(Collectors.groupingBy(Person::getName, Collectors.groupingBy(Person::getSalary)));

Mapping (map)

String[] arr = {"abcd","bcdd","defde","ftr"};
Arrays.stream(arr).map(String::toUpperCase).forEach(System.out::println);
personList.stream().map(Person::getSalary).forEach(System.out::println);
List
increased = personList.stream().map(p -> { p.setSalary(p.getSalary()+10000); return p; }).collect(Collectors.toList());

Sorting (sorted)

String[] strs = {"abc","m","M","bcd"};
System.out.println(Arrays.stream(strs).sorted().collect(Collectors.toList())); // [M, abc, bcd, m]
Arrays.stream(strs).sorted(Comparator.comparing(String::length)).forEach(System.out::println);

Stream Extraction and Combination

Stream
s1 = Stream.of(arr1);
Stream
s2 = Stream.of(arr2);
Stream.concat(s1, s2).distinct().forEach(System.out::println);
Stream.iterate(1, x -> x + 2).limit(10).forEach(System.out::println);
Stream.iterate(1, x -> x + 2).skip(1).limit(5).forEach(System.out::println);

The article concludes with a list of additional interview‑question resources and a call‑to‑action for readers to follow the associated public account for more Java interview material.

JavaAPICollectionsstreamFunctionalProgramming
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login 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.