简体   繁体   English

Java 8 Streams中的可变参数

[英]Mutable parameters in Java 8 Streams

Looking at this question: How to dynamically do filtering in Java 8? 看看这个问题: 如何在Java 8中动态进行过滤?

The issue is to truncate a stream after a filter has been executed. 问题是在执行过滤器后截断流。 I cant use limit because I dont know how long the list is after the filter. 我不能使用限制,因为我不知道列表在过滤器后多长时间。 So, could we count the slements after the filter? 那么,我们可以算一下过滤器之后的数据吗?

So, I thought I could create a class that counts and pass the stream through a map. 所以,我想我可以创建一个计数并通过地图传递流的类。 The code is in this answer . 代码就在这个答案中

I created a class that counts but leave the elements unaltered, I use a Function here, to avoid to use the lambdas I used in the other answer: 我创建了一个重要的类,但保持元素不变,我在这里使用一个函数,以避免使用我在另一个答案中使用的lambda:

class DoNothingButCount<T > implements Function<T, T> {
    AtomicInteger i;
    public DoNothingButCount() {
        i = new AtomicInteger(0);
    }
    public T apply(T p) {
        i.incrementAndGet();
        return p;
    }
}

So my Stream was finally: 所以我的流终于:

persons.stream()
    .filter(u -> u.size > 12)
    .filter(u -> u.weitght > 12)
    .map(counter)
    .sorted((p1, p2) -> p1.age - p2.age)
    .collect(Collectors.toList())
    .stream()
    .limit((int) (counter.i.intValue() * 0.5))
    .sorted((p1, p2) -> p2.length - p1.length)
    .limit((int) (counter.i.intValue() * 0.5 * 0.2)).forEach((p) -> System.out.println(p));

But my question is about another part of the my example. 但我的问题是关于我的例子的另一部分。

collect(Collectors.toList()).stream().

If I remove that line the consequences are that the counter is ZERO when I try to execute limit. 如果我删除该行,结果是当我尝试执行限制时计数器为零。 I am somehow cheating the "efectively final" requirement by using a mutable object. 我通过使用可变对象以某种方式欺骗“有效最终”要求。

I may be wrong, but I iunderstand that the stream is build first, so if we used mutable objects to pass parameters to any of the steps in the stream these will be taken when the stream is created. 我可能错了,但我理解流是首先构建的,所以如果我们使用可变对象将参数传递给流中的任何步骤,这些将在创建流时进行。

My question is, if my assumption is right, why is this needed? 我的问题是,如果我的假设是正确的,为什么需要它呢? The stream (if non parallel) could be pass sequentially through all the steps (filter, map..) so this limitation is not needed. 流(如果非并行)可以顺序通过所有步骤(过滤器,映射..),因此不需要此限制。

Short answer 简短的回答

My question is, if my assumption is right, why is this needed? 我的问题是,如果我的假设是正确的,为什么需要它呢? The stream (if non parallel) could be pass sequentially through all the steps (filter, map..) so this limitation is not needed. 流(如果非并行)可以顺序通过所有步骤(过滤器,映射..),因此不需要此限制。

As you already know, for parallel streams, this sounds pretty obvious: this limitation is needed because otherwise the result would be non deterministic. 正如您所知,对于并行流,这听起来很明显:需要这种限制,否则结果将是非确定性的。

Regarding non-parallel streams, it is not possible because of their current design: each item is only visited once. 关于非并行流,由于它们当前的设计,它是不可能的:每个项目只访问一次。 If streams did work as you suggest, they would do each step on the whole collection before going to the next step, which would probably have an impact on performance , I think. 如果Stream确实按你的建议工作,他们会在进入下一步之前对整个集合执行每一步,这可能会对性能产生影响 ,我想。 I suspect that's why the language designers made that decision. 我怀疑这就是语言设计师做出这个决定的原因。


Why it technically does not work without collect 为什么没有collect在技​​术上不起作用

You already know that, but here is the explanation for other readers. 你已经知道了,但这是其他读者的解释。 From the docs : 来自文档

Streams are lazy; 溪流很懒; computation on the source data is only performed when the terminal operation is initiated, and source elements are consumed only as needed. 仅在启动终端操作时执行对源数据的计算,并且仅在需要时消耗源元素。

Every intermediate operation of Stream , such as filter() or limit() is actually just some kind of setter that initializes the stream's options. Stream每个中间操作 ,例如filter()limit()实际上只是某种初始化流选项的setter。

When you call a terminal operation , such as forEach() , collect() or count() , that's when the computation happens, processing items following the pipeline previously built. 当您调用终端操作时 ,例如forEach()collect()count() ,就在计算发生时,处理先前构建的管道之后的项目。

This is why limit() 's argument is evaluated before a single item has gone through the first step of the stream. 这就是在单个项目完成流的第一步之前评估limit()的参数的原因。 That's why you need to end the stream with a terminal operation, and start a new one with the limit() you'll then know. 这就是为什么你需要用终端操作结束流,然后用你将知道的limit()开始一个新的。

More detailed answer about why not allow it for parallel streams 关于为什么不允许它用于并行流的更详细的答案

Let your stream pipeline be step X > step Y > step Z . 让您的流管道为step X > step Y > step Z

We want parallel treatment of our items. 我们想要平行处理我们的物品。 Therefore, if we allow step Y's behavior to depend on the items that already went through X, then Y is non deterministic. 因此,如果我们允许步骤Y的行为依赖于已经通过X的项目,那么Y是非确定性的。 This is because at the moment an item arrives at step Y, the set of items that have already gone through X won't be the same across multiple executions (because of the threading). 这是因为在项目到达步骤Y的那一刻,已经通过X的项目集在多次执行中将是不同的(因为线程)。

More detailed answer about why not allow it for non-parallel streams 关于为什么不允许它用于非并行流的更详细的答案

A stream, by definition, is used to process the items in a flow . 根据定义,流用于处理中的项目。 You could think of a non-parallel stream as follows: one single item goes through all the steps, then the next one goes through all the steps, etc. In fact, the doc says it all: 你可以想到一个非并行流如下:一个单项经过所有步骤,然后下一个经过所有步骤,等等。事实上,doc说明了一切:

The elements of a stream are only visited once during the life of a stream. 流的元素仅在流的生命期间访问过一次。 Like an Iterator, a new stream must be generated to revisit the same elements of the source. 与迭代器一样,必须生成新流以重新访问源的相同元素。

If streams didn't work like this, it wouldn't be any better than just do each step on the whole collection before going to the next step. 如果stream不能像这样工作,那么在进行下一步之前,完成整个集合的每一步都不会更好。 That would actually allow mutable parameters in non-parallel streams, but it would probably have a performance impact (because we would iterate multiple times over the collection). 实际上允许非并行流中的可变参数 ,但它可能会对性能产生影响(因为我们会在集合上多次迭代)。 Anyway, their current behavior does not allow what you want. 无论如何,他们目前的行为不允许你想要的东西。

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

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