Groovy两种任务过滤遍历代码写法 哪种性能更优?
Groovy两种遍历过滤写法性能对比结论
第二种写法性能显著差于第一种,不存在优化效果,反而会引入额外开销和潜在逻辑bug,具体原因拆解如下:
- 你对第一种写法的性能顾虑不成立:不管逻辑写在filter里还是写在for循环里,
state == "ready"这个纯内存判断的执行顺序、遍历开销完全一致,不存在“先筛ready再遍历多走一次循环”的额外损耗——毕竟你就算把所有条件塞到filter闭包,第一个判断的还是state,不符合的直接跳过,这部分开销和第一种写法没有任何区别。 - 第二种写法的核心性能问题来自重复API调用:Groovy的
&&确实是短路求值(前一个条件不满足就不会执行后一个),但你在闭包里写了两次processAPI.getProcess(it.processId):对每个state为ready的任务,第一次调用getProcess做日期校验,只要日期校验通过,就会发起第二次getProcess调用做objectId校验。如果processAPI.getProcess是数据库查询、远程RPC这类IO密集操作,多出来的这一次调用开销会远大于循环本身的开销,数据量越大性能差距越明显。 - 第二种写法还存在逻辑风险:如果两次getProcess调用之间process数据发生了并发更新,可能出现两次返回结果不一致的情况,导致过滤逻辑出错。
性能最优的写法
直接把过滤逻辑合并到单次遍历中,按「判断开销从低到高」排列条件,最大化短路收益,每个任务最多只调用一次getProcess,也不需要生成中间结果集占用内存:
for (def task : taskList) { // 优先做零开销的内存字段判断,不符合直接跳过 if (task.state != "ready") { continue } // 仅对state符合的任务发起一次API查询 def process = processAPI.getProcess(task.processId) // 后续判断依次短路,不满足直接跳过 if (process.endDate?.format(dateFormat2) <= dateFrom) { continue } if (process.objectId <= 0) { continue } // 执行业务逻辑 }
这个写法相比你原来的两种方案:
- 比第一种写法少了中间
taskResult列表的内存占用,少了一次遍历中间集合的开销 - 比第二种写法完全消除了重复的getProcess调用,IO开销直接减半(部分数据场景下开销降低幅度会更大)
- 不存在重复调用API导致的数据不一致问题
内容的提问来源于stack exchange,提问作者N.D.H.Vu
相关产品推荐
相关产品推荐

