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<UserPo> 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<UserPo> filterList = list.stream()
            .filter(p -> null != p.getScore())
            .collect(Collectors.toList());
        System.out.println("Student info:");
        filterList.forEach(System.out::println);

        List<Double> 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<Double, List<UserPo>> groupByScoreMap = list.stream()
            .filter(p -> null != p.getScore())
            .collect(Collectors.groupingBy(UserPo::getScore));
        for (Map.Entry<Double, List<UserPo>> 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);
    }
}
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.

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

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.