# 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);
    });

🛠️ Auto-refactor Available

You can auto-refactor this with jSparrow.
Drop this button to your Eclipse IDE workspace to install jSparrow for free:

Drag to your running Eclipse* workspace. *Requires Eclipse Marketplace Client

Need help? Check out our installation guide.

# Properties

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