双重for循环优化

26 篇文章 0 订阅

项目中有段代码逻辑是个双重for循环,发现数据量大的时候,直接导致数据接口响应超时,这里记录下不断优化的过程,算是抛砖引玉吧~
Talk is cheap,show me your code!

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循环

@Test
	void 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条件

	@Test
	void 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、使用迭代器来删除内层循环中已使用或判断过的元素,减少循环次数

	@Test
	void 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)来实现检索

	@Test
	void 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集合特性均能够有效提升查询效率。

  • 4
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值