【问题标题】:order of execution of map().map() in Java streamsJava 流中 map().map() 的执行顺序
【发布时间】:2020-09-20 16:26:28
【问题描述】:

我使用以下代码(简化):
主要:

Foe[] foe = Stream.of(foe_2).map(Mapper_1).map(Mapper_2).toArray(Foe::new);

在 Mapper_1 中:

{
  System.out.println("Mapper_1");
  do stuff
}

在 Mapper_2 中:

{
  System.out.println("Mapper_2");
  do other stuff
}

我需要在 Mapper_2 启动之前完成 Mapper_1。
Mapper_1和Mapper_2调用的函数互不调用!

我的预期:
Mapper_1 映射Stream.of(foe_2) 返回的流的所有元素,然后 Mapper_2 映射到输出数组,得到这个输出:

Mapper_1  
...  
Mapper_1  
Mapper_2  
...  
Mapper_2    

持续发生的事情:
Mapper_1 映射Stream.of(foe_2) 的第一个元素,紧随其后,Mapper_2 获取第一个结果并将其映射,准备好放入输出数组,然后 Mapper_1 映射第二个元素,从而产生以下输出:

Mapper_1  
Mapper_2  
NullpointerExcpetion  

我得到了异常,因为 Mapper_1 没有映射所有元素并且数据结构混乱。

这是正常的行为,对我来说会违反直觉,还是我错过了什么?

【问题讨论】:

  • 你能分享更多关于 Mapper_1 和 Mapper_2 应该做什么的细节吗?
  • Mapper_1 加载一些数据。 Mapper_2 处理这些数据(构建有点像一个双链表,每个有 2 个下一个和前一个元素),但需要所有数据,否则会遇到空指针

标签: java java-stream


【解决方案1】:

Streams 一次处理 1 个元素,因此您看到的行为实际上是 JDK 规范所要求的。

要通过映射器 1 处理所有元素,然后通过映射器 2 处理所有元素,您需要一个接一个地处理 2 个流,并在将元素传递给第二个流之前收集中间的第一个流.

但别担心;你可以用一行来表达:

Foe[] foe = Stream.of(foe_2)
  .map(Mapper_1)
  .collect(toList()).stream()
  .map(Mapper_2)
  .toArray(Foe::new)

【讨论】:

    【解决方案2】:

    您看到的行为是预期的,甚至是必要的,因为流可能是无限的。流仅在终端操作要求它提供一个项目时“生成”一个项目,并且当发生这种情况时,将为该单个项目执行整个步骤链。

    所以当toArray被执行时,它会要求流产生第一项,通过Mapper_1映射然后Mapper_2,然后是第二项,通过Mapper_1映射然后@ 987654326@等

    如果您需要 Mapper_1 在转到 Mapper_2 之前查看所有项目,那么您需要先收集到中间集合或数组中,然后再将其流式传输到 Mapper_2

    例如

    Foe[] foe = Stream.of(foe_2)
        .map(Mapper_1)
        .collect(Collectors.toList())
        .stream().map(Mapper_2)
        .toArray(Foe[]::new);
    

    但是,如果您的映射器是无状态的并且不依赖于查看所有项目,那会更好。

    另见Java 8 stream operations execution order

    【讨论】:

      猜你喜欢
      • 2020-01-03
      • 2013-08-13
      • 1970-01-01
      • 2022-06-10
      • 2015-07-07
      • 2022-06-18
      • 1970-01-01
      • 2021-02-01
      • 1970-01-01
      相关资源
      最近更新 更多