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)
如果我删除该行,结果是当我尝试执行限制时计数器为零.我通过使用可变对象以某种方式欺骗"有效最终"要求.
我可能错了,但我理解流是首先构建的,所以如果我们使用可变对象将参数传递给流中的任何步骤,则在创建流时将采用这些步骤.
我的问题是,如果我的假设是正确的,为什么需要这样做?流(如果非并行)可以顺序通过所有步骤(过滤器,映射..),因此不需要此限制.
我的问题是,如果我的假设是正确的,为什么需要这样做?流(如果非并行)可以顺序通过所有步骤(过滤器,映射..),因此不需要此限制.
正如您所知,对于并行流,这听起来非常明显:需要这种限制,否则结果将是非确定性的.
关于非并行流,由于它们当前的设计,它是不可能的:每个项目只访问一次.如果Stream确实按你的建议工作,他们会在进入下一步之前对整个集合执行每一步,这可能会对性能产生影响,我想.我怀疑这就是语言设计师做出这个决定的原因.
collect你已经知道了,但这是其他读者的解释.来自文档:
溪流很懒; 仅在启动终端操作时执行对源数据的计算,并且仅在需要时消耗源元素.
每一个中间操作的Stream,如filter()或limit()其实只是某种二传手的初始化流的选项.
当您调用终端操作时,例如forEach(),collect()或者count(),当计算发生时,处理先前构建的管道之后的项目.
这就是为什么limit()在单个项目完成流的第一步之前评估参数的原因.这就是为什么你需要通过终端操作结束流,并开始一个新的,limit()你会知道.
让你的流管道step X > step Y > step Z.
我们想要平行处理我们的物品.因此,如果我们允许步骤Y的行为依赖于已经通过X的项目,那么Y是非确定性的.这是因为在项目到达步骤Y的那一刻,已经通过X的项目集在多次执行中将是不同的(因为线程).
根据定义,流用于处理流中的项.你可以想到一个非并行流如下:一个单项经过所有步骤,然后下一个经过所有步骤,等等.事实上,doc说明了一切:
流的元素仅在流的生命期间访问过一次.与迭代器一样,必须生成新流以重新访问源的相同元素.
如果stream不能像这样工作,那么在进行下一步之前,完成整个集合的每一步都不会更好.这实际上允许非并行流中的可变参数,但它可能会对性能产生影响(因为我们会在集合上多次迭代).无论如何,他们目前的行为不允许你想要的东西.