Java流能否将点列表转换为它们的坐标列表?

Java流能否将点列表转换为它们的坐标列表?,java,mapping,java-stream,variable-expansion,Java,Mapping,Java Stream,Variable Expansion,我有一个JavaFX8程序中的Point3Ds流。为了从它们创建网格,我希望能够生成它们(x,y,z)坐标的列表 通过传统的Java循环,这是一个足够简单的任务。(实际上几乎微不足道)然而,在未来,我可能要处理数万个问题;我非常希望能够使用Java流API,并通过并行流实现这一点 我想我要找的大概相当于这个伪代码: List<Double> coordinates = stream.parallel().map(s -> (s.getX(), s.getY(), s.getZ(

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

通过传统的Java循环,这是一个足够简单的任务。(实际上几乎微不足道)然而,在未来,我可能要处理数万个问题;我非常希望能够使用Java流API,并通过并行流实现这一点

我想我要找的大概相当于这个伪代码:

List<Double> coordinates = stream.parallel().map(s -> (s.getX(), s.getY(), s.getZ())).collect(Collectors.asList());
List 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());
列表坐标=
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.3毫秒的时间内完成,即10000分。
没什么

让我们尝试将计数从10000增加到10000000(跳过预热):

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运行引起的

结论:过早优化不好


你是说你想要一个包含
{x1,y1,z1,x2,y2,z2,x3,y3,z3,…,xn,yn,zn}
的无差别
列表吗?是的,无差别列表是一个很好的表达方式。非常好+1.然而,尽管这完美地回答了如何做到这一点的问题,但它实际上忽略了通过使用并行流来提高性能的隐含目标。从某种意义上说,看看为什么;但我可能会反驳说,编程的另一个领域是人的因素。运行函数处理的单行代码通常比七行或八行代码块更容易让程序员理解,尤其是在牺牲只会使它稍微慢一点的情况下。(记者法则)此外,正如您所指出的,GC可以调整。尽管如此,我还是很感激你注意到,在这种情况下,它实际上使处理稍微慢了一点。我的使用将在稍后的阶段涉及OpenCL,我想缓冲将掩盖这一点;以防以后出现问题。@Michaelericoblin当然,如果您的理由是代码更简单,那么您的问题中“我可能要处理数万点”部分的要点是什么,还是“用并行流完成此任务”的后续内容?这让人觉得你这么做的主要原因是为了获得性能,我想使用并行流,这就是我要解决的问题。如果您想要的只是更简单的代码,那么您的问题应该是“我如何处理流?”好吧,也许更清楚地表达我的担忧是,似乎应该可以执行这样的流映射;如果可能的话,我倾向于使用更新的API。它们的存在是因为Java6不再是现代硬件的最佳选择,只是因为它在技术上可以运行。这意味着我的理解有一个错误,这就是堆栈溢出的原因。@MichaelEricOberlin并行处理对于提高重/慢任务的可伸缩性非常有用,但您的示例远不是很重,而且您正在将结果收集到一个列表中,因此最后它仍然必须序列化所有内容,创建单线程瓶颈。在适当的地方使用新特性,使用流使代码更简单是好的,但是使用并行处理不是。仅仅因为功能是新的并不能使它在所有方面都更好。