# Replace Nested Loops with flatMap

# Description

Compound data structures similar to Collection<Collection<T>> are fairly common. This rule finds the nested invocations of Stream::forEach which are used to iterate over such data structures and replaces them with single invocations of Stream::flatMap (opens new window). Using flatMap() not only makes the code more readable and but also allows for additional combinations with other Stream operations.

# Benefits

Arguably, a flattened stream is easier to read.

# Tags

# Code Changes

# Iterating over nested collections

Pre

    List<List<User>> groups = findGroups();
    groups.forEach(group -> {
        group.forEach(user -> {
            sendAward(user);
        });
    });

Post

    List<List<User>> groups = findGroups();
    groups.stream()
        .flatMap(group -> group.stream())
        .forEach(user -> {
            sendAward(user);
        });

# Nested Stream::forEach

Pre

orders.stream()
    .map(Order::getOrderItems)
    .forEach(items -> {
        items.forEach(item -> {
            Product product = item.getProduct();
            int quantity = item.getQuantity();
            add(product, quantity);
        });
    });

Post

orders.stream()
    .map(Order::getOrderItems)
    .flatMap(items -> items.stream())
    .forEach(item -> {
        Product product = item.getProduct();
        int quantity = item.getQuantity();
        add(product, quantity);
    });

# Deep nested loops

Pre

    matrix3.stream().filter(row -> !row.isEmpty()).forEach(row -> {
        row.stream().filter(col -> !col.isEmpty()).forEach(col -> {
            col.stream().filter(cell -> !cell.isEmpty()).forEach(cell -> {
                cell.stream().filter(element -> !element.isEmpty()).map(element -> element.substring(0, 1)).forEach(element -> {
                    System.out.print(element);
                });
            });
        });
    });

Post

matrix3.stream().filter(row -> !row.isEmpty()).flatMap(row -> row.stream())
    .filter(col -> !col.isEmpty())
    .flatMap(col -> col.stream())
    .filter(cell -> !cell.isEmpty())
    .flatMap(cell -> cell.stream())
    .filter(element -> !element.isEmpty())
    .map(element -> element.substring(0, 1))
    .forEach(element -> {
        System.out.print(element);
    });

Use a Java Refactoring Tool

No license required

You can review this refactoring on your code without a license by installing jSparrow to your Eclipse IDE. Install the plug-in from Eclipse IDE: Eclipse Marketplace.

System-wide Refactoring

Do you want to automate this refactoring (and many more) to your system-wide code? The automatic application of this system-wide refactoring can be unlocked by acquiring your jSparrow license.

a drawn cute bird pointing at a graph that shows positive results

# Properties

Property Value
Rule ID FlatMapInsteadOfNestedLoops
First seen in jSparrow version 2.2.0
Minimum Java version 8
Remediation cost 15 min