Java 8 Streams中的可变参数

时间:2014-04-07 12:38:58

标签: java java-8 java-stream

看看这个问题:How to dynamically do filtering in Java 8?

问题是在执行过滤器后截断流。我不能使用limit因为我不知道列表在过滤器之后有多长。那么,我们可以计算过滤器之后的数据吗?

所以,我想我可以创建一个计算并通过地图传递流的类。The code is in this answer

我创建了一个重要的类但保持元素不变,我在这里使用了一个函数,以避免使用我在另一个答案中使用的lambdas:

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

所以我的Stream终于来了:

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));

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

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

如果我删除该行,结果是当我尝试执行限制时计数器为零。我在某种程度上欺骗了#34; efectively final&#34;通过使用可变对象的要求。

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

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

1 个答案:

答案 0 :(得分:8)

简短回答

  

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

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

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


为什么在没有collect

的情况下技术上不起作用

你已经知道了,但这是其他读者的解释。 来自the docs

  流是懒惰的;仅对源数据进行计算   当启动终端操作时,源元素是   只在需要时消费。

Stream的每个中间操作,例如filter()limit()实际上只是某种初始化流选项的setter。

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

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

关于为什么不允许并行流

的更详细的答案

让您的流管道为step X > step Y > step Z

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

关于为什么不允许非并行流

的更详细的答案

根据定义,流用于处理中的项目。你可以想到一个非并行流如下:一个单项完成所有步骤,然后下一个完成所有步骤,等等。实际上,文档说明了一切:

  

流的元素仅在a的生命期间访问过一次   流。像Iterator一样,必须生成一个新的流来重新访问   源的相同元素。

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