Backend Development 9 min read

Optimizing Nested Loops in Java: Using break and HashMap for Significant Performance Gains

This article analyzes a common Java scenario of nested for‑loops over large user and user‑memo lists, demonstrates the performance impact of adding a break statement, and shows how converting the inner list to a HashMap can reduce execution time from tens of seconds to a few seconds.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Optimizing Nested Loops in Java: Using break and HashMap for Significant Performance Gains

In many Java code reviews, developers write nested for‑loops to match items from two large collections, such as a List<User> and a List<UserMemo> , which leads to poor performance.

Scenario example: For each User we need to find the corresponding UserMemo by userId and process its content .

Data size used for the demonstration: 50,000 User objects and 30,000 UserMemo objects.

Initial implementation (nested loops without break):

import lombok.Data;

@Data
public class User {
    private Long userId;
    private String name;
}

import lombok.Data;

@Data
public class UserMemo {
    private Long userId;
    private String content;
}

public static List
getUserTestList() {
    List
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
getUserMemoTestList() {
    List
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;
}

public static void main(String[] args) {
    List
userTestList = getUserTestList();
    List
userMemoTestList = getUserMemoTestList();
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    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 业务处理......" + content);
            }
        }
    }
    stopWatch.stop();
    System.out.println("最终耗时" + stopWatch.getTotalTimeMillis());
}

The above code iterates 5 × 10⁴ × 3 × 10⁴ ≈ 1.5 billion comparisons, taking about 26,857 ms on the test machine.

Optimization 1 – add break after a match is found:

public static void main(String[] args) {
    List
userTestList = getUserTestList();
    List
userMemoTestList = getUserMemoTestList();
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    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 业务处理......" + content);
                break;
            }
        }
    }
    stopWatch.stop();
    System.out.println("最终耗时" + stopWatch.getTotalTimeMillis());
}

With the break, execution time drops to roughly 10‑12 seconds, roughly halving the cost.

Optimization 2 – replace the inner loop with a HashMap lookup:

public static void main(String[] args) {
    List
userTestList = getUserTestList();
    List
userMemoTestList = getUserMemoTestList();
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    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 业务处理......" + content);
        }
    }
    stopWatch.stop();
    System.out.println("最终耗时" + stopWatch.getTotalTimeMillis());
}

Using a map reduces the time complexity from O(N·M) to O(N+M); the measured execution time falls to about 2‑3 seconds, a dramatic improvement.

The article also includes a snippet of the JDK 8 HashMap.getNode implementation to illustrate why hash‑based lookups are near O(1) under normal conditions, and notes that only a pathological scenario where all keys collide would degrade performance to O(N).

Overall, the piece teaches backend developers how a simple break and a proper use of HashMap can turn a costly nested iteration into an efficient linear‑time operation.

BackendJavaPerformanceOptimizationHashMapnested-loop
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

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.