Simplifying Java Code with Stream API: From Filtering to Grouping

This article explains how Java 8's Lambda expressions and Stream API enable concise, declarative processing of collections—showing pre‑Java 8 versus Java 8 implementations for filtering, sorting, mapping, and grouping dishes, and covering core stream concepts, creation methods, intermediate and terminal operations.

Top Architect
Top Architect
Top Architect
Simplifying Java Code with Stream API: From Filtering to Grouping

Java 8 introduced Lambda expressions and the Stream API, which together enable declarative processing of collections, making code more concise and readable.

Using Streams to Simplify Common Tasks

Example: filter dishes with calories < 400, sort them, and collect their names.

public class Dish {
    private String name;
    private boolean vegetarian;
    private int calories;
    private Type type;
    // getters and setters
}

Pre‑Java 8 Implementation

private List<String> beforeJava7(List<Dish> dishList) {
    List<Dish> lowCaloricDishes = new ArrayList<>();
    // 1. filter
    for (Dish dish : dishList) {
        if (dish.getCalories() < 400) {
            lowCaloricDishes.add(dish);
        }
    }
    // 2. sort
    Collections.sort(lowCaloricDishes, new Comparator<Dish>() {
        @Override
        public int compare(Dish o1, Dish o2) {
            return Integer.compare(o1.getCalories(), o2.getCalories());
        }
    });
    // 3. extract names
    List<String> lowCaloricDishesName = new ArrayList<>();
    for (Dish d : lowCaloricDishes) {
        lowCaloricDishesName.add(d.getName());
    }
    return lowCaloricDishesName;
}

Java 8 Implementation

private List<String> afterJava8(List<Dish> dishList) {
    return dishList.stream()
            .filter(d -> d.getCalories() < 400)   // filter
            .sorted(comparing(Dish::getCalories)) // sort
            .map(Dish::getName)                  // extract name
            .collect(Collectors.toList());       // collect
}

New requirement: group dishes by their type and return a Map<Type, List<Dish>>. Pre‑Java 8 solution uses explicit loops and map management.

private static Map<Type, List<Dish>> beforeJdk8(List<Dish> dishList) {
    Map<Type, List<Dish>> result = new HashMap<>();
    for (Dish dish : dishList) {
        if (result.get(dish.getType()) == null) {
            List<Dish> dishes = new ArrayList<>();
            dishes.add(dish);
            result.put(dish.getType(), dishes);
        } else {
            result.get(dish.getType()).add(dish);
        }
    }
    return result;
}

With Stream API the same task is a single line:

private static Map<Type, List<Dish>> afterJdk8(List<Dish> dishList) {
    return dishList.stream().collect(groupingBy(Dish::getType));
}

Core Stream Concepts

A stream is a sequence of elements supporting aggregate operations; it is not a data structure and does not store elements. Streams are created from collections, arrays, files, or functions.

Creating Streams

From a collection:

List<Integer> list = Arrays.asList(1,2,3); Stream<Integer> s = list.stream();

From an array: int[] arr = {1,2,3}; IntStream s = Arrays.stream(arr); From values: Stream<Integer> s = Stream.of(1,2,3); From a file: Stream<String> lines = Files.lines(Paths.get("data.txt")); From functions: Stream<Integer> s = Stream.iterate(0, n -> n + 2).limit(5); or

Stream<Double> s = Stream.generate(Math::random).limit(5);

Intermediate Operations

Operations such as filter, distinct, limit, skip, map, flatMap transform a stream and return a new stream. They are lazy and executed only when a terminal operation is invoked.

Terminal Operations

Terminal operations include forEach, collect, reduce, count, min, max, findFirst, anyMatch, etc., which trigger the processing of the pipeline and produce a result or side‑effect.

Conclusion

Using the Stream API dramatically reduces boilerplate, improves readability, and encourages a functional style of programming in Java back‑end development.

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 programmingCollectionsStream API
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

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.