繁体   English   中英

Java Streams可以将点列表转换为坐标列表吗?

[英]Can Java Streams transform a list of points into a list of their coordinates?

我在JavaFX 8程序中有Point3D流。 为了从中创建网格,我希望能够生成它们的(x,y,z)坐标列表。

通过传统的Java循环,这已经足够简单了。 (实际上,这几乎是微不足道的。)但是,将来,我可能会处理成千上万的积分; 我非常希望能够使用Java Stream API并通过并行流完成此任务。

我想我要找的是这个伪代码的大致等效项:

List<Double> coordinates = stream.parallel().map(s -> (s.getX(), s.getY(), s.getZ())).collect(Collectors.asList());

到目前为止,我还没有发现任何此类功能。 有人可以请我朝正确的方向推进吗?

您可以使用flatMap

List<Double> coordinates = 
    stream.parallel()
          .flatMap(s -> Stream.of(s.getX(), s.getY(), s.getZ()))
          .collect(Collectors.asList());

为什么? 即使有了“成千上万的点”,代码也将在极短的时间内完成,并且“使用并行流”将不会真正获得任何收益。

这听起来像是一个过早优化的完美示例,您可能会将代码复杂化为尚不存在的问题,并且至少在这种情况下不可能成为问题。

为了证明我的观点,我在下面创建了测试代码。

为了最大程度地减少GC运行的影响,我使用-Xms10g -Xmx10g运行了此代码,并添加了显式的gc()调用,因此测试运行使用“干净的状态”运行。

与往常一样,性能测试受JIT优化和其他因素的影响,因此提供了一个预热循环。

public static void main(String[] args) {
    Random rnd = new Random();
    List<Point3D> input = new ArrayList<>();
    for (int i = 0; i < 10_000; i++)
        input.add(new Point3D(rnd.nextDouble(), rnd.nextDouble(), rnd.nextDouble()));

    for (int i = 0; i < 100; i++) {
        test1(input);
        test2(input);
    }

    for (int i = 0; i < 10; i++) {
        long start1 = System.nanoTime();
        test1(input);
        long end1 = System.nanoTime();
        System.gc();
        long start2 = System.nanoTime();
        test2(input);
        long end2 = System.nanoTime();
        System.gc();
        System.out.printf("%.6f  %.6f%n", (end1 - start1) / 1_000_000d, (end2 - start2) / 1_000_000d);
    }
}
private static List<Double> test1(List<Point3D> input) {
    List<Double> list = new ArrayList<>();
    for (Point3D point : input) {
        list.add(point.getX());
        list.add(point.getY());
        list.add(point.getZ());
    }
    return list;
}
private static List<Double> test2(List<Point3D> input) {
    return input.stream().parallel()
                         .flatMap(s -> Stream.of(s.getX(), s.getY(), s.getZ()))
                         .collect(Collectors.toList());
}

结果

0.355267  0.392904
0.205576  0.260035
0.193601  0.232378
0.194740  0.290544
0.193601  0.238365
0.243497  0.276286
0.200728  0.243212
0.197022  0.240646
0.192175  0.239790
0.198162  0.279708

没有什么大的区别,尽管并行流似乎稍微慢一些。
另请注意,它在不到0.3 ms的时间内完成了10,000点。
没什么!

让我们尝试将计数从10,000增加到10,000,000(跳过预热):

433.716847  972.100743
260.662700  693.263850
250.699271  736.744653
250.486281  813.615375
249.722716  714.296997
254.704145  796.566859
254.713840  829.755767
253.368331  959.365322
255.016928  973.306254
256.072177  1047.562090

现在并行流有一定的降级。 慢了3倍 这可能是由于额外的GC运行引起的。

结论:过早的优化是不好的!!!!

就您而言,您实际上使情况更糟。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM