Java中如何对自定义Point对象列表用reduce计算Route路径总距离
错误原因
你使用的双参数reduce重载要求初始值、累加器返回值都和流元素类型保持一致。你传入的初始值是double类型的0d,流里的元素是自定义点类型T,累加器返回的distance计算结果也是double,和要求返回的T类型不匹配,因此触发类型错误。
优先用reduce的实现方案
需要用三参数的reduce重载,通过自定义累加容器同时保存上一个点和当前累计距离,实现类型转换:
兼容低版本Java的实现
public double routeDistance() { // 点数小于2时总距离为0 if (points.size() < 2) { return 0d; } // 用Object数组作为状态容器:下标0存上一个点,下标1存累计距离 return (double) points.stream().reduce( new Object[]{null, 0d}, (acc, currentPoint) -> { T prevPoint = (T) acc[0]; // 第一个点只初始化状态不计算距离 if (prevPoint == null) { acc[0] = currentPoint; return acc; } double currentTotal = (double) acc[1] + prevPoint.distance(currentPoint); return new Object[]{currentPoint, currentTotal}; }, // 并行流的合并逻辑,串行场景也可兼容 (acc1, acc2) -> { T acc1Last = (T) acc1[0]; T acc2Last = (T) acc2[0]; if (acc1Last == null) return acc2; if (acc2Last == null) return acc1; double mergeTotal = (double) acc1[1] + (double) acc2[1] + acc1Last.distance(acc2Last); return new Object[]{acc2Last, mergeTotal}; } )[1]; }
Java 16+ 更优雅的record实现
// 在Route类内部定义静态累加器容器 private record DistanceAccumulator<T>(T lastPoint, double total) {} public double routeDistance() { if (points.size() < 2) { return 0d; } return points.stream().reduce( new DistanceAccumulator<T>(null, 0d), (acc, current) -> { if (acc.lastPoint() == null) { return new DistanceAccumulator<>(current, 0d); } double newTotal = acc.total() + acc.lastPoint().distance(current); return new DistanceAccumulator<>(current, newTotal); }, (acc1, acc2) -> { if (acc1.lastPoint() == null) return acc2; if (acc2.lastPoint() == null) return acc1; double mergeTotal = acc1.total() + acc2.total() + acc1.lastPoint().distance(acc2.lastPoint()); return new DistanceAccumulator<>(acc2.lastPoint(), mergeTotal); } ).total(); }
更简洁的替代方案
如果对reduce没有强要求,用IntStream遍历索引的实现更简单易维护:
public double routeDistance() { return IntStream.range(0, points.size() - 1) .mapToDouble(i -> points.get(i).distance(points.get(i + 1))) .sum(); }
如果你的points是LinkedList等非随机访问列表,可以先转成数组再计算,避免多次遍历的性能损耗。
内容的提问来源于stack exchange,提问作者syydi
相关产品推荐
相关产品推荐

