Backend Development 9 min read

Optimizing Nested Loops in Java Using Map for Faster ID Matching

This article demonstrates how to replace inefficient nested for‑loops that match user IDs between two large lists with a map‑based lookup, showing code examples, performance measurements, and the impact of using break statements and O(1) hash map access to dramatically reduce execution time.

Top Architect
Top Architect
Top Architect
Optimizing Nested Loops in Java Using Map for Faster ID Matching

In many projects developers write nested for loops to find matching IDs between two collections, which leads to poor performance when the data size grows. The author presents a concrete scenario: a User list (≈50,000 items) and a UserMemo list (≈30,000 items) where each UserMemo contains a userId and a content string.

First, the naive implementation iterates the User list and, for each user, scans the entire UserMemo list to locate the matching userId . The code looks like this:

for (User user : userTestList) {
    Long userId = user.getUserId();
    for (UserMemo userMemo : userMemoTestList) {
        if (userId.equals(userMemo.getUserId())) {
            String content = userMemo.getContent();
            System.out.println("业务处理..." + content);
        }
    }
}

Running this on the simulated data (5 W users × 3 W memos) takes about 26 857 ms. Adding a break after processing the first match cuts the time roughly in half (≈10 000 ms) because the inner loop no longer continues after finding the needed record.

The real optimization replaces the inner loop with a Map that stores userId → content for all UserMemo objects. The map is built once using Java 8 streams:

Map
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("业务处理..." + content);
    }
}

With this approach the total execution time drops to about 1 200 ms, a dramatic improvement. The reason is the change in time complexity: the nested loops have O(N × M) complexity, while the map lookup is O(1) on average, resulting in O(N + M) overall.

The article also includes the data‑generation helpers used for the benchmark:

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

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

Finally, the author explains the underlying hash‑based mechanism of HashMap in JDK 8, noting that hash collisions are rare and that the average lookup cost stays close to O(1). The article concludes by encouraging readers to adopt map‑based lookups whenever a one‑to‑one relationship exists between two collections.

backendJavaperformanceOptimizationmapnested-loop
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

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.