如何用Java BufferedReader高效过滤日志生成测试用例执行摘要?
优化思路与解答
1. 核心优化方向:用Map跟踪已创建的TestcaseSummary
你的思路完全正确——只扫描一次文件的优化能带来非常明显的性能提升,尤其是当日志文件很大、测试用例数量较多的时候。原来的实现是O(N*M)复杂度(N是测试用例数,M是日志行数),优化后会降到O(M),差距会随着N和M的增大越来越显著。
具体实现上,不要直接往List里塞对象,而是先用一个Map<String, TestcaseSummary>来跟踪每个测试用例的统计数据:
- 遍历日志的每一行,解析出测试用例名称和状态
- 检查Map中是否已有该用例的
TestcaseSummary:- 如果没有,就新建一个对象,初始化计数(比如当前状态是passed,就把amount和passed设为1,failed设为0),然后放入Map
- 如果已经存在,就直接更新对应的计数(passed/failed/amount加1)
- 遍历完所有日志行后,把Map中的值全部转成List返回即可
2. 具体代码示例
public List<TestcaseSummary> createTestcaseSummaryList(String pathToRegressionFile) throws IOException { // 先拿到所有需要统计的测试用例名称,存到Set里方便快速判断 Set<String> validTestcaseNames = new HashSet<>(); for (Testcase testcase : daoTestcaseName.getTestcaseList()) { validTestcaseNames.add(testcase.getName()); } Map<String, TestcaseSummary> summaryMap = new HashMap<>(); try (BufferedReader br = new BufferedReader(new FileReader(pathToRegressionFile))) { String line; while ((line = br.readLine()) != null) { // 先解析行数据,这里假设用|分割,注意处理空格 String[] parts = line.split("\\|"); if (parts.length < 3) { // 跳过格式不正确的行 continue; } String testcaseName = parts[1].trim(); String status = parts[2].trim(); // 只统计我们关心的测试用例 if (!validTestcaseNames.contains(testcaseName)) { continue; } // 检查Map中是否已有该用例的摘要 TestcaseSummary summary = summaryMap.get(testcaseName); if (summary == null) { // 初始化新的摘要对象 int passed = "passed".equals(status) ? 1 : 0; int failed = "failed".equals(status) ? 1 : 0; summary = new TestcaseSummary(testcaseName, 1, passed, failed); summaryMap.put(testcaseName, summary); } else { // 更新已有摘要的计数 summary.setAmount(summary.getAmount() + 1); if ("passed".equals(status)) { summary.setPassed(summary.getPassed() + 1); } else if ("failed".equals(status)) { summary.setFailed(summary.getFailed() + 1); } } } } // try-with-resources会自动关闭流,比原来的catch关闭更安全 // 把Map转成List返回 return new ArrayList<>(summaryMap.values()); }
3. 关键细节说明
- 用Set存储有效测试用例名:避免统计日志中出现的、不在我们测试用例列表里的条目,同时
contains操作是O(1),效率很高 - try-with-resources语法:自动关闭BufferedReader,不用手动在catch里处理,代码更简洁安全
- 解析日志行的方式:用
split("\\|")分割后记得trim(),因为你的日志格式里|前后有空格,直接取的话会带空格,导致匹配失败 - 性能提升的验证:假设你有100个测试用例,日志有10000行,原来的实现要读100*10000=1,000,000行,优化后只需要读10000行,差距非常明显;如果日志更大(比如100万行),优化后的速度会快100倍左右
4. 对你疑问的逐一解答
- 是否立即创建对象并存入列表?:不建议直接存列表,因为列表的查找是O(N),每次判断是否存在都要遍历列表,效率低。用Map的话查找是O(1),更适合这种动态更新的场景,最后转成List即可。
- 如何检查对象是否已创建?:通过Map的
get(testcaseName)方法,如果返回null说明还没创建,否则直接更新已有对象的计数。 - 是否有性能提升?:绝对有,而且随着测试用例数和日志行数的增加,提升效果会越来越显著,属于典型的时间复杂度优化,从O(N*M)降到O(M)。
内容的提问来源于stack exchange,提问作者user10417331
相关产品推荐
相关产品推荐

