当前位置: 首页 > 知识库问答 >
问题:

Java流操作融合与有状态中间操作

欧阳英彦
2023-03-14

我一直试图理解和展示Java流如何在引擎盖下实现一种类型的循环融合,从而可以将几个操作融合到一个pass中。

这里的第一个例子是:

Stream.of("The", "cat", "sat", "on", "the", "mat")
        .filter(w -> {
            System.out.println("Filtering: " + w);
            return w.length() == 3;
        })
        .map(w -> {
            System.out.println("Mapping: " + w);
            return w.toUpperCase();
        })
        .forEach(w -> System.out.println("Printing: " + w));

具有以下输出(对每一个元素的单一传递融合相当清楚):

Filtering: The
Mapping: The
Printing: THE
Filtering: cat
Mapping: cat
Printing: CAT
Filtering: sat
Mapping: sat
Printing: SAT
Filtering: on
Filtering: the
Mapping: the
Printing: THE
Filtering: mat
Mapping: mat
Printing: MAT
Stream.of("The", "cat", "sat", "on", "the", "mat")
        .filter(w -> {
            System.out.println("Filtering: " + w);
            return w.length() == 3;
        })
        .sorted()
        .map(w -> {
            System.out.println("Mapping: " + w);
            return w.toUpperCase();
        })
        .forEach(w -> System.out.println("Printing: " + w));
Filtering: The
Filtering: cat
Filtering: sat
Filtering: on
Filtering: the
Filtering: mat
Mapping: The
Printing: THE
Mapping: cat
Printing: CAT
Mapping: mat
Printing: MAT
Mapping: sat
Printing: SAT
Mapping: the
Printing: THE

所以我的问题是,在调用distinct时,我认为因为它是一个“有状态”的中间操作,所以它不允许在(所有操作的)一次传递过程中单独处理单个元素,这是正确的吗。此外,因为sorted()状态操作需要处理整个输入流以产生结果,所以这里不能部署融合技术,所以这就是为什么首先进行所有过滤,然后在排序之后将映射和打印操作融合在一起?如果我的假设有任何不正确的地方,请予以纠正,并请随意阐述我已经说过的内容。

此外,它如何决定是否可以将元素融合到一个单一的传递中,例如,当distinct()操作存在时,是否只有一个标志来关闭以阻止它发生,就像当distinct()不存在时所做的那样?

最后一个问题是,将操作融合到一次操作中的好处有时是显而易见的,例如,当与短路结合时。将filter-map-forEach或甚至filter-map-sum等操作融合在一起的主要好处是什么?

共有1个答案

林涵映
2023-03-14

对无状态操作(map、filter、flatMap、peek等)进行了充分融合;我们构建一个级联consumer对象链,并将数据注入其中。每个元素都可以相互独立地操作,因此在链中永远不会有任何“卡住”的东西。(这就是Louis所说的如何实现融合的意思--我们将各个阶段组成一个大函数,并将数据提供给它。)

有状态操作(distinct,sorted,limit,等等)更复杂,它们的行为变化更大。每个有状态操作都可以选择它想要如何实现自己,因此它可以选择尽可能少的侵入性方法。例如,distince(在某些情况下)允许元素在被审查时显示出来,而sorted是一个完整的障碍。(区别在于懒惰的可能性有多大,以及他们处理无限源之类的事情的能力有多强,而下游的操作是有限的。)

诚然,有状态操作通常会破坏融合的一些好处,但不是全部(上游和下游的操作仍然可以被融合。)

 类似资料:
  • 问题内容: 以下说法正确吗? 该操作是“有状态的中间操作”,这意味着后续操作不再对后备集合进行操作,而是对内部状态进行操作。 (来源和来源 -它们似乎是彼此复制或来自同一来源。) 我已经从上面的源代码中测试了一个片段: 有用。我换成用,并且: 令我惊讶的是,它被抛出了。 所有测试的方法都遵循有状态的中间操作特性。但是,这种独特的行为没有得到记录,Stream操作和管道部分也没有说明 有状态中间操作

  • 我有一个对象,“item”,字段为:int:id string:prices 字符串prices包含一个或多个由逗号分隔的价格值。 getStoresaIntList()从对象中的字符串价格返回价格值列表。 以上当然不是我想要的。

  • 注意:我不一定要寻找下面描述的具体示例问题的解决方案。我真的很感兴趣,为什么这在java 8中是不可能的。 Java流是懒惰的。最后,他们有一个单一的终端操作<我的解释是,这个终端操作将通过流提取所有值。没有任何中间操作可以做到这一点。为什么没有中间操作通过流拉入任意数量的元素?类似这样: 当下游操作尝试推进流一次时,中间操作可能尝试多次(或根本不推进)上游。 我会看到几个用例: (这些只是示例。

  • 在faygo中,操作与中间件使用同一个接口实现,因此实际上每次请求调用的是一条有序、步阶可控的操作链。 操作链在每次请求中匹配到路由后被调用执行。 操作与中间件的接口定义: Handler interface { Serve(ctx *Context) error } 通常我们使用function或struct来实现操作或中间件。 从业务层面区分操作与中间件: 每个URL对应的操作链[]Han

  • 问题内容: 是否可以保证在使用流时,中间操作将按程序顺序执行?我怀疑是这种情况,否则会导致非常细微的错误,但我找不到确切的答案。 例: 是否保证总是返回或?(如果最后一次映射操作在第一次映射操作之前执行,则可能会引发异常- 类似地,如果过滤器在第二次映射操作之后执行,则“ b”将保留在最终列表中) 问题答案: 之所以出现这个问题,是因为您正在从一种类型映射到同一类型。如果您考虑要执行的正式操作,那