如何使用Java 8 Stream将相邻线段列表分组?
用Java 8 Stream将相邻线段分组
我有一个由LineDetailsTO对象(包含start和end属性)组成的列表,示例输入如下:
[[P1,P2],[P2,P3],[P10,P11],[P11,P12],[P12,P13]]
需要把前一条线段的end与后一条的start相等的相邻线段归为同一子列表,最终得到:
[[[P1,P2],[P2,P3]],[[P10,P11],[P11,P12],[P12,P13]]]
我试过collect、reduce和groupBy方法但没成功,现在有一段可读性较差的实现代码,想知道怎么用Java 8 Stream更优雅地完成这个分组功能。
现有实现代码:
private static List<List<LineDetailsTO>> groupOverlappingMultipartLines(List<LineDetailsTO> overlappingMultipartLines){ List<List<LineDetailsTO>> grouped = overlappingMultipartLines.stream() .collect(Collector.of(ArrayList::new, (groupedLines, currentLine) -> { if(groupedLines.isEmpty()) { groupedLines.add(new ArrayList<>(Arrays.asList(currentLine))); } else { List<LineDetailsTO> lastGroup = groupedLines.get(groupedLines.size() - 1); LineDetailsTO lastLine = lastGroup.get(lastGroup.size() - 1); if(lastLine.getEnd().equals(currentLine.getStart())){ lastGroup.add(currentLine); } else { groupedLines.add(new ArrayList<>(Arrays.asList(currentLine))); } } }, (left, right) -> {left.addAll(right); return left;})); return grouped; }
优化后的Stream实现
你的核心逻辑是正确的,只是可以通过语义化命名、拆分逻辑块、完善并行场景兼容来提升可读性和健壮性:
private static List<List<LineDetailsTO>> groupConnectedLines(List<LineDetailsTO> lines) { return lines.stream() .collect(Collector.of( // 供应器:创建存放分组的容器 ArrayList::new, // 累加器:处理每一条线段,判断加入现有分组还是新建分组 (groups, currentLine) -> { if (groups.isEmpty()) { groups.add(new ArrayList<>(Collections.singletonList(currentLine))); return; } // 获取最后一个分组及组内最后一条线段 List<LineDetailsTO> lastGroup = groups.get(groups.size() - 1); LineDetailsTO lastLine = lastGroup.get(lastGroup.size() - 1); if (lastLine.getEnd().equals(currentLine.getStart())) { lastGroup.add(currentLine); } else { groups.add(new ArrayList<>(Collections.singletonList(currentLine))); } }, // 合并器:并行流场景下,合并两个分组列表(处理跨列表的连续线段) (leftGroups, rightGroups) -> { if (leftGroups.isEmpty()) return rightGroups; if (rightGroups.isEmpty()) return leftGroups; // 检查左右列表是否可以首尾连接 List<LineDetailsTO> leftLastGroup = leftGroups.get(leftGroups.size() - 1); LineDetailsTO leftLastLine = leftLastGroup.get(leftLastGroup.size() - 1); List<LineDetailsTO> rightFirstGroup = rightGroups.get(0); LineDetailsTO rightFirstLine = rightFirstGroup.get(0); if (leftLastLine.getEnd().equals(rightFirstLine.getStart())) { leftLastGroup.addAll(rightFirstGroup); rightGroups.remove(0); } leftGroups.addAll(rightGroups); return leftGroups; } )); }
优化说明
- 语义化命名:把
groupedLines改为groups,让变量作用更直观 - 替换工具方法:用
Collections.singletonList替代Arrays.asList,更贴合“创建单元素列表”的语义,避免Arrays.asList的固定大小列表特性带来的潜在问题 - 完善并行流支持:原合并器只是简单拼接列表,优化后会检查左右分组列表的首尾线段是否连续,确保并行流场景下结果正确
- 逻辑拆分:通过空行和注释分割不同逻辑块,降低阅读成本
如果追求极致的可读性,也可以把“判断是否连续”的逻辑抽成单独方法,比如:
private static boolean isContinuous(LineDetailsTO prev, LineDetailsTO curr) { return prev.getEnd().equals(curr.getStart()); }
然后在累加器和合并器中调用这个方法,进一步简化代码。
内容的提问来源于stack exchange,提问作者Susitha Ravinda Senarath
相关产品推荐
相关产品推荐

