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

时间:2016-01-27 19:28:22

标签: java mapping java-stream variable-expansion

我在JavaFX 8程序中有一个Point3D流。我想,为了从它们创建一个Mesh,能够生成一个(x,y,z)坐标列表。

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

我想我正在寻找的是这个伪代码的粗略等价物:

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

到目前为止,我还没有找到这样的功能。有人可以帮我推动正确的方向吗?

2 个答案:

答案 0 :(得分:4)

您可以使用flatMap

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

答案 1 :(得分:0)

为什么呢?即使使用了数以万计的积分,这些代码也会在很短的时间内完成,而且你并没有真正获得任何东西&#34;并行流#34;

这听起来像是premature optimization的一个完美示例,在这种情况下,您可能会使代码复杂化而不是一个问题,而且至少在这种情况下不可能是一个。

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

为了最大限度地减少GC运行的影响,我使用-Xms10g -Xmx10g运行此代码,并添加了明确的gc()调用,因此测试运行使用&#34; clean slate&#34;。

与往常一样,性能测试受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());
}

RESULT

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

没有重大区别,尽管并行流看起来有点慢 另请注意,对于10,000点,它在小于0.3毫秒内完成 它什么都没有!

让我们尝试将计数从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运行引起的。

结论:过早优化很糟糕!!!!

在你的情况下,你实际上做得更糟。