You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Java Stream API计算坐标路径长度且无需额外容器类?

问题

我有一个包含多个Coordinate对象的List,每个Coordinate对象包含x和y坐标,该类提供distanceTo(Coordinate coord)方法,用于返回当前对象与目标coord对象之间的距离。

现在需要计算由List<Coordinate> path表示的路径总长度,想通过Java Stream API实现,可能用到reduce、collect或mapToDouble等方法,但没找到合适的方案。曾找到类似问题的解答,但该方案需要新建类,对当前场景来说过于繁琐。

是否存在无需额外创建类的优雅实现方案?

示例代码:

import java.util.List;

public class Main {
    public static void main(String[] args) {
        Coordinate c1 = new Coordinate(0, 0);
        Coordinate c2 = new Coordinate(0, 1);
        Coordinate c3 = new Coordinate(1, 1);
        Coordinate c4 = new Coordinate(1, 2);

        List<Coordinate> path = List.of(c1, c2, c3, c4);

        // 基础实现方案
        double pathLength = 0;
        for (int i = 0; i < path.size() - 1; i++) {
            pathLength += path.get(i).distanceTo(path.get(i + 1));
        }

        // Stream实现位置
    }

    public static class Coordinate {
        private final int x;
        private final int y;

        public Coordinate(int x, int y) {
            this.x = x;
            this.y = y;
        }

        public double distanceTo(Coordinate coord) {
            return Math.hypot(x - coord.x, y - coord.y);
        }
    }
}
解决方案

方法1:IntStream索引遍历(推荐)

直接通过索引流获取相邻坐标对,计算距离后求和,逻辑与原for循环完全一致,简洁高效:

double totalLength = IntStream.range(0, path.size() - 1)
    .mapToDouble(i -> path.get(i).distanceTo(path.get(i + 1)))
    .sum();

这种方式无需额外类,可读性强,性能和传统循环接近,是最优选择。

方法2:用AtomicReference记录前序坐标

借助AtomicReference存储前一个坐标元素,遍历过程中计算相邻距离:

import java.util.concurrent.atomic.AtomicReference;

// ...

AtomicReference<Coordinate> prevCoord = new AtomicReference<>();
double totalLength = path.stream()
    .mapToDouble(curr -> {
        Coordinate prev = prevCoord.getAndSet(curr);
        return prev == null ? 0 : prev.distanceTo(curr);
    })
    .sum();

第一个元素因无前序坐标返回0,后续元素均计算与前一个坐标的距离,最终求和得到总长度。AtomicReference支持并行流场景的线程安全,顺序流下也能正常工作。

方法3:reduce结合数组临时存储

利用reduce的累积特性,用数组存储总长度和前序坐标(避免新建类),但逻辑相对复杂:

double totalLength = path.stream()
    .reduce(new double[]{0, 0, 0}, // 数组元素:[总长度, 前序x, 前序y]
        (acc, curr) -> {
            // 处理第一个元素,仅记录坐标
            if (acc[1] == 0 && acc[2] == 0 && path.indexOf(curr) == 0) {
                acc[1] = curr.x;
                acc[2] = curr.y;
                return acc;
            }
            // 非第一个元素,计算距离并累加
            acc[0] += new Coordinate((int) acc[1], (int) acc[2]).distanceTo(curr);
            // 更新前序坐标为当前坐标
            acc[1] = curr.x;
            acc[2] = curr.y;
            return acc;
        },
        // 并行流合并逻辑,单线程可忽略
        (acc1, acc2) -> {
            acc1[0] += acc2[0];
            return acc1;
        })[0];

注意:path.indexOf(curr)在大列表中会有性能损耗,仅适合小数据量场景,实际开发中不推荐这种方式。


内容的提问来源于stack exchange,提问作者Wewius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 03:31:37