Backend Development 8 min read

Boost Java Loop Performance: Replace Nested Loops with a HashMap

This article demonstrates how to dramatically speed up Java code that matches items between two large lists by eliminating nested loops, using early‑exit with break and, more effectively, pre‑building a HashMap for O(1) lookups, with concrete timing results and full code examples.

macrozheng
macrozheng
macrozheng
Boost Java Loop Performance: Replace Nested Loops with a HashMap

When you need to find matching IDs between two collections—such as a

User

list and a

UserMemo

list—many developers write a nested

for

loop, which becomes extremely slow as the data size grows.

Example entity classes:

<code>@Data
public class User {
    private Long userId;
    private String name;
}
</code>
<code>@Data
public class UserMemo {
    private Long userId;
    private String content;
}
</code>

Test data generation creates 50,000

User

objects and 30,000

UserMemo

objects.

<code>public static List<User> getUserTestList() {
    List<User> users = new ArrayList<>();
    for (int i = 1; i <= 50000; i++) {
        User user = new User();
        user.setName(UUID.randomUUID().toString());
        user.setUserId((long) i);
        users.add(user);
    }
    return users;
}

public static List<UserMemo> getUserMemoTestList() {
    List<UserMemo> userMemos = new ArrayList<>();
    for (int i = 30000; i >= 1; i--) {
        UserMemo userMemo = new UserMemo();
        userMemo.setContent(UUID.randomUUID().toString());
        userMemo.setUserId((long) i);
        userMemos.add(userMemo);
    }
    return userMemos;
}
</code>

Naïve nested loop implementation:

<code>for (User user : userTestList) {
    Long userId = user.getUserId();
    for (UserMemo userMemo : userMemoTestList) {
        if (userId.equals(userMemo.getUserId())) {
            String content = userMemo.getContent();
            System.out.println("Processing content: " + content);
        }
    }
}
</code>

This approach iterates 5 × 10⁴ × 3 × 10⁴ ≈ 1.5 billion comparisons, taking about 26,857 ms on the test data.

Adding a

break

after finding the first match reduces the inner loop work, cutting the time to roughly 10,000 ms .

For a scalable solution, pre‑populate a

Map&lt;Long, String&gt;

from the

UserMemo

list and then perform a single lookup per user:

<code>public static void main(String[] args) {
    List<User> userTestList = getUserTestList();
    List<UserMemo> userMemoTestList = getUserMemoTestList();

    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    // Build map: userId → content
    Map<Long, String> contentMap = userMemoTestList.stream()
        .collect(Collectors.toMap(UserMemo::getUserId, UserMemo::getContent));

    for (User user : userTestList) {
        Long userId = user.getUserId();
        String content = contentMap.get(userId);
        if (StringUtils.hasLength(content)) {
            System.out.println("Processing content: " + content);
        }
    }

    stopWatch.stop();
    System.out.println("Final time: " + stopWatch.getTotalTimeMillis());
}
</code>

Running this version drops the execution time to just a few hundred milliseconds, because the map provides average‑case O(1) access.

The improvement stems from changing the algorithmic complexity from quadratic (

O(n²)

) to linear (

O(n)

). A hash‑based map hashes the

userId

to an array index, yielding near‑constant lookup time; collisions are rare with Java 8’s hash function, and even in the worst case the cost degrades only to

O(log n)

or

O(n)

for a single bucket.

Javaperformance optimizationAlgorithmBackend DevelopmentHashMapNested Loops
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

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.