程序员的最大失误:滥用双层For循环引发Web应用性能隐患
别再用双层for循环比对List了!百万用户级优化方案安排上
兄弟,我太懂这种事后拍大腿的懊恼了!双层for循环比对List属性,看似简单直接,但确实是性能杀手——时间复杂度直接拉到O(n²),用户量小的时候没啥感觉,真到百万级数据,卡顿甚至系统崩溃绝对找上门。
咱拿你说的已登录用户场景举例子,先看看原来的坑人写法:
// 原来的双层循环写法 List<String> loggedInUsers = getLoggedInUsernames(); List<User> allUsers = getAllUsers(); List<User> usersToReturn = new ArrayList<>(); for (User user : allUsers) { boolean isLoggedIn = false; for (String username : loggedInUsers) { if (user.getUsername().equals(username)) { isLoggedIn = true; break; } } if (isLoggedIn) { usersToReturn.add(user); } }
这种写法要是遇上allUsers和loggedInUsers各10万条数据,得执行10亿次比较,想想都头皮发麻。下面给你两种靠谱的优化方案:
方案1:用HashSet做快速查找
HashSet的contains()方法是O(1)时间复杂度,先把其中一个List转成HashSet,再遍历另一个List做判断,整体时间复杂度直接降到O(n):
// 优化后的HashSet写法 List<String> loggedInUsers = getLoggedInUsernames(); Set<String> loggedInUserSet = new HashSet<>(loggedInUsers); // 转成Set List<User> allUsers = getAllUsers(); List<User> usersToReturn = new ArrayList<>(); for (User user : allUsers) { if (loggedInUserSet.contains(user.getUsername())) { usersToReturn.add(user); } }
方案2:用HashMap匹配复杂对象
如果需要比对的是自定义对象的多个属性,或者要快速获取匹配的对象,可以用HashMap把关键属性作为key:
// 用HashMap匹配自定义对象 List<User> loggedInUserObjects = getLoggedInUserObjects(); Map<String, User> loggedInUserMap = new HashMap<>(); for (User user : loggedInUserObjects) { loggedInUserMap.put(user.getUsername(), user); // 用用户名做key } List<User> allUsers = getAllUsers(); List<User> usersToReturn = new ArrayList<>(); for (User user : allUsers) { if (loggedInUserMap.containsKey(user.getUsername())) { // 要是需要还能直接拿到匹配的登录用户对象 User matchedUser = loggedInUserMap.get(user.getUsername()); usersToReturn.add(user); } }
额外注意点
- 如果是自定义对象作为HashSet元素或HashMap的key,一定要正确重写
equals()和hashCode()方法,不然查找会直接失效。 - 要是用Java 8+,还能结合Stream API让代码更简洁:
List<User> usersToReturn = allUsers.stream() .filter(user -> loggedInUserSet.contains(user.getUsername())) .collect(Collectors.toList());
赶紧把这些地方改了吧,等用户量上来再优化就被动了!
内容的提问来源于stack exchange,提问作者user9658240
相关产品推荐
相关产品推荐

