项目中有段代码逻辑是个双重for循环,发现数据量大的时候,直接导致数据接口响应超时,这里记录下不断优化的过程,算是抛砖引玉吧~
Talk is cheap,show me your code!
双重for循环优化
- 1、数据准备
- 2、原始双重for循环
- 3、直接使用双重for循环查询条件,增加break条件
- 4、使用迭代器来删除内层循环中已使用或判断过的元素,减少循环次数
- 5、把要筛选的信息写成map集合,遍历List时用map.get(key)来实现检索
- 6、总结
1、数据准备
Order
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Order {private Integer orderId;private String orderName;
}
OrderDetail
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class OrderDetail {private Integer orderDetailId;private Integer orderId;private String orderNums;private String orderAddress;
}
造测试数据
public static List<Order> getOrderTestList() {List<Order> orders = new ArrayList<>();for (int i = 1; i <= 50000; i++) {Order order = new Order();order.setOrderName(UUID.randomUUID().toString());order.setOrderId(i);orders.add(order);}return orders;}public static List<OrderDetail> getOrderDetailTestList() {List<OrderDetail> orderDetails = new ArrayList<>();for (int i = 30000; i >= 1; i--) {OrderDetail orderDetail = new OrderDetail();orderDetail.setOrderAddress(UUID.randomUUID().toString());orderDetail.setOrderId(i);orderDetail.setOrderDetailId(i);orderDetails.add(orderDetail);}return orderDetails;}
2、原始双重for循环
@Testvoid test3() {List<Order> orderTestList = getOrderTestList();List<OrderDetail> orderDetailTestList = getOrderDetailTestList();StopWatch stopWatch = new StopWatch();stopWatch.start();// 直接使用双重for循环查询条件for (Order order : orderTestList) {int orderId = order.getOrderId();for (OrderDetail orderDetail : orderDetailTestList) {if(orderId == orderDetail.getOrderId() ){System.out.println("模拟数据orderAddress 业务处理......" + orderDetail.getOrderAddress());}}}stopWatch.stop();System.out.println("最终耗时" + stopWatch.getTotalTimeMillis());}
执行结果
3、直接使用双重for循环查询条件,增加break条件
@Testvoid test3() {List<Order> orderTestList = getOrderTestList();List<OrderDetail> orderDetailTestList = getOrderDetailTestList();StopWatch stopWatch = new StopWatch();stopWatch.start();// 直接使用双重for循环查询条件,增加break条件for (Order order : orderTestList) {int orderId = order.getOrderId();for (OrderDetail orderDetail : orderDetailTestList) {if(orderId == orderDetail.getOrderId() ){System.out.println("模拟数据orderAddress 业务处理......" + orderDetail.getOrderAddress());break;}}}stopWatch.stop();System.out.println("最终耗时" + stopWatch.getTotalTimeMillis());}
执行结果
4、使用迭代器来删除内层循环中已使用或判断过的元素,减少循环次数
@Testvoid test3() {List<Order> orderTestList = getOrderTestList();List<OrderDetail> orderDetailTestList = getOrderDetailTestList();StopWatch stopWatch = new StopWatch();stopWatch.start();// 使用迭代器来删除内层循环中已使用或判断过的元素,减少循环次数for (Order order : orderTestList) {ListIterator<OrderDetail> orderDetailListIterator = orderDetailTestList.listIterator();int orderId = order.getOrderId();while (orderDetailListIterator.hasNext()) {OrderDetail nextOrderDetail = orderDetailListIterator.next();if(orderId == nextOrderDetail.getOrderId() ){System.out.println("模拟数据orderAddress 业务处理......" + nextOrderDetail.getOrderAddress());orderDetailListIterator.remove();}}}stopWatch.stop();System.out.println("最终耗时" + stopWatch.getTotalTimeMillis());}
执行结果
5、把要筛选的信息写成map集合,遍历List时用map.get(key)来实现检索
@Testvoid test3() {List<Order> orderTestList = getOrderTestList();List<OrderDetail> orderDetailTestList = getOrderDetailTestList();StopWatch stopWatch = new StopWatch();stopWatch.start();//使用stream() 记得一定要判空Map<Integer, String> orderAddressMap =orderDetailTestList.stream().collect(Collectors.toMap(OrderDetail::getOrderId, OrderDetail::getOrderAddress));for (Order order : orderTestList) {int orderId = order.getOrderId();String orderAddress = orderAddressMap.get(orderId);if (StringUtils.hasLength(orderAddress)) {System.out.println("模拟数据orderAddress 业务处理......" + orderAddress);}}if (StringUtils.hasLength(orderAddress)) {System.out.println("模拟数据orderAddress 业务处理......" + orderAddress);}stopWatch.stop();System.out.println("最终耗时" + stopWatch.getTotalTimeMillis());}
测试结果
6、总结
可以看出,通过迭代删除或者利用map集合特性均能够有效提升查询效率。