Java 8 Streams中的可变参数

Rau*_*uiu 3 java java-8 java-stream

看看这个问题:如何在Java 8中动态进行过滤?

问题是在执行过滤器后截断流.我不能使用限制,因为我不知道列表在过滤器后多长时间.那么,我们可以算一下过滤器之后的数据吗?

所以,我想我可以创建一个计数并通过地图传递流的类.代码就在这个答案中.

我创建了一个重要的类,但保持元素不变,我在这里使用一个函数,以避免使用我在另一个答案中使用的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;
    }
}
Run Code Online (Sandbox Code Playgroud)

所以我的流终于:

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));
Run Code Online (Sandbox Code Playgroud)

但我的问题是关于我的例子的另一部分.

collect(Collectors.toList()).stream().
Run Code Online (Sandbox Code Playgroud)

如果我删除该行,结果是当我尝试执行限制时计数器为零.我通过使用可变对象以某种方式欺骗"有效最终"要求.

我可能错了,但我理解流是首先构建的,所以如果我们使用可变对象将参数传递给流中的任何步骤,则在创建流时将采用这些步骤.

我的问题是,如果我的假设是正确的,为什么需要这样做?流(如果非并行)可以顺序通过所有步骤(过滤器,映射..),因此不需要此限制.

Jof*_*rey 8

简短的回答

我的问题是,如果我的假设是正确的,为什么需要这样做?流(如果非并行)可以顺序通过所有步骤(过滤器,映射..),因此不需要此限制.

正如您所知,对于并行流,这听起来非常明显:需要这种限制,否则结果将是非确定性的.

关于非并行流,由于它们当前的设计,它是不可能的:每个项目只访问一次.如果Stream确实按你的建议工作,他们会在进入下一步之前对整个集合执行每一步,这可能会对性能产生影响,我想.我怀疑这就是语言设计师做出这个决定的原因.


为什么它在技术上不起作用 collect

你已经知道了,但这是其他读者的解释.来自文档:

溪流很懒; 仅在启动终端操作时执行对源数据的计算,并且仅在需要时消耗源元素.

每一个中间操作Stream,如filter()limit()其实只是某种二传手的初始化流的选项.

当您调用终端操作时,例如forEach(),collect()或者count(),当计算发生时,处理先前构建的管道之后的项目.

这就是为什么limit()在单个项目完成流的第一步之前评估参数的原因.这就是为什么你需要通过终端操作结束流,并开始一个新的,limit()你会知道.

关于为什么不允许它用于并行流的更详细的答案

让你的流管道step X > step Y > step Z.

我们想要平行处理我们的物品.因此,如果我们允许步骤Y的行为依赖于已经通过X的项目,那么Y是非确定性的.这是因为在项目到达步骤Y的那一刻,已经通过X的项目集在多次执行中将是不同的(因为线程).

关于为什么不允许它用于非并行流的更详细的答案

根据定义,流用于处理中的项.你可以想到一个非并行流如下:一个单项经过所有步骤,然后下一个经过所有步骤,等等.事实上,doc说明了一切:

流的元素仅在流的生命期间访问过一次.与迭代器一样,必须生成新流以重新访问源的相同元素.

如果stream不能像这样工作,那么在进行下一步之前,完成整个集合的每一步都不会更好.这实际上允许非并行流中的可变参数,但它可能会对性能产生影响(因为我们会在集合上多次迭代).无论如何,他们目前的行为不允许你想要的东西.