Backend Development 11 min read

Java 8 Stream API: Declarative Data Processing with PO/VO Examples

This article introduces Java 8's Stream API, explains its SQL‑like pipeline operations such as filter, map, sorted, collect and parallelStream, and demonstrates practical PO/VO processing with comprehensive code examples and performance considerations.

Architect's Tech Stack
Architect's Tech Stack
Architect's Tech Stack
Java 8 Stream API: Declarative Data Processing with PO/VO Examples

Java 8 added a new abstraction called Stream, allowing data to be processed in a declarative way.

Streams provide an intuitive, SQL‑like approach to operate on Java collections, offering a high‑level abstraction for collection manipulation.

This style treats the collection of elements as a stream that flows through a pipeline where each node can perform operations such as filtering, sorting, or aggregation.

Linux users will recognize the similarity to the pipe (|) operator; the concept is essentially the same.

Compared with traditional for‑loop iteration, stream code is shorter and clearer, especially when handling multiple PO/VO objects, avoiding the "Russian doll" nesting that makes the code hard to read.

Stream

+--------------------+       +------+   +------+   +---+   +-------+
| stream of elements +----->|filter+->|sorted+->|map+->|collect|
+--------------------+       +------+   +------+   +---+   +-------+

PO Code

All following operations use the UserPo class.

filter

filter: selects elements that satisfy a condition, discarding the rest.

// Count students whose score is not null
long count = list.stream().filter(p -> null != p.getScore()).count();

map

map: transforms each element into a new form, commonly used to extract fields from PO/VO objects.

// Extract all student scores
List<Double> scoreList = list.stream().map(p -> p.getScore()).collect(Collectors.toList());
// Join all student names into a comma‑separated string
String nameString = list.stream().map(p -> p.getName()).collect(Collectors.joining(","));

sorted

sorted: orders the stream according to a specified comparator; adding .reversed() sorts in descending order.

// Sort by score in descending order
List<UserPo> filterList = list.stream()
    .filter(p -> null != p.getScore())
    .sorted(Comparator.comparing(UserPo::getScore).reversed())
    .collect(Collectors.toList());

forEach

forEach: performs a custom action on each element; unlike other operations it can modify the original collection.

// Print each element
filterList.forEach(System.out::println);

collect

collect: aggregates the stream, useful for grouping, converting to a list, or joining strings.

// Group by score
Map<Double, List<UserPo>> groupByScoreMap = list.stream()
    .filter(p -> null != p.getScore())
    .collect(Collectors.groupingBy(UserPo::getScore));
// Convert to list
List<Double> scoreList = list.stream().map(UserPo::getScore).collect(Collectors.toList());
// Join names
String nameString = list.stream().map(UserPo::getName).collect(Collectors.joining(","));

statistics

statistics: provides summary statistics such as min, max, sum, average, and count.

DoubleSummaryStatistics stats = filterList.stream()
    .mapToDouble(UserPo::getScore)
    .summaryStatistics();
System.out.println("max=" + stats.getMax());
System.out.println("min=" + stats.getMin());
System.out.println("sum=" + stats.getSum());
System.out.println("avg=" + stats.getAverage());

parallelStream

parallelStream: executes stream operations in parallel using multiple threads, which can improve performance but lacks thread‑local context.

long parallelCount = list.parallelStream()
    .filter(p -> null != p.getScore())
    .count();

Complete Code

package com.cmx.tcn.stream;
/**
 * @author: Cai MinXing
 * @create: 2020-03-25 18:17
 */
public class UserPo {
    private String name;
    private Double score;
    public UserPo(String name, Double score) {
        this.name = name;
        this.score = score;
    }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public Double getScore() { return score; }
    public void setScore(Double score) { this.score = score; }
    @Override
    public String toString() {
        return "UserPo{" + "name='" + name + '\'' + ", score=" + score + '}';
    }
}
package com.cmx.tcn.stream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * @author: Cai MinXing
 * @create: 2020-03-25 18:15
 */
public class StreamTest {
    public static void main(String[] args) {
        List
list = new ArrayList<>();
        list.add(new UserPo("XiaoYi", 10.0));
        list.add(new UserPo("XiaoWu", 50.0));
        list.add(new UserPo("XiaoLiu", 60.0));
        list.add(new UserPo("Xiao6", 60.0));
        list.add(new UserPo("XiaoKong", null));
        list.add(new UserPo("XiaoJiu", 90.0));

        long count = list.stream().filter(p -> null != p.getScore()).count();
        System.out.println("Number of students who took the exam: " + count);

        List
filterList = list.stream()
            .filter(p -> null != p.getScore())
            .collect(Collectors.toList());
        System.out.println("Student info:");
        filterList.forEach(System.out::println);

        List
scoreList = list.stream().map(UserPo::getScore).collect(Collectors.toList());
        System.out.println("All scores: " + scoreList);

        String nameString = list.stream().map(UserPo::getName).collect(Collectors.joining(","));
        System.out.println("All names: " + nameString);

        filterList = list.stream()
            .filter(p -> null != p.getScore())
            .sorted(Comparator.comparing(UserPo::getScore).reversed())
            .collect(Collectors.toList());
        System.out.println("Scores sorted descending:");
        filterList.forEach(System.out::println);

        Map
> groupByScoreMap = list.stream()
            .filter(p -> null != p.getScore())
            .collect(Collectors.groupingBy(UserPo::getScore));
        for (Map.Entry
> entry : groupByScoreMap.entrySet()) {
            System.out.println("Score: " + entry.getKey() + " Count: " + entry.getValue().size());
        }

        // Increase each score by 10
        filterList.forEach(p -> p.setScore(p.getScore() + 10));
        System.out.println("Add 10 points to each student");
        filterList.forEach(System.out::println);

        long passCount = filterList.stream().filter(p -> p.getScore() >= 60).count();
        System.out.println("Number of passing students: " + passCount);

        DoubleSummaryStatistics statistics = filterList.stream()
            .mapToDouble(UserPo::getScore)
            .summaryStatistics();
        System.out.println("Max: " + statistics.getMax());
        System.out.println("Min: " + statistics.getMin());
        System.out.println("Sum: " + statistics.getSum());
        System.out.println("Avg: " + statistics.getAverage());

        long parallelCount = list.parallelStream().filter(p -> null != p.getScore()).count();
        System.out.println("Parallel stream count: " + parallelCount);
    }
}
JavaData ProcessinglambdaFunctional ProgrammingStream APIParallel Stream
Architect's Tech Stack
Written by

Architect's Tech Stack

Java backend, microservices, distributed systems, containerized programming, and more.

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.