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

Java 8 流中的可变参数

佴涵蓄
2023-03-14

看这个问题:如何在Java8中动态做过滤?

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

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

我创建了一个可计数的类,但保持元素不变,我在这里使用了一个函数,以避免使用我在另一个答案中使用的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;
    }
}

所以我的流最终是:

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().

如果我删除这一行,结果是当我试图执行limit时,计数器为零。不知何故,我通过使用一个可变对象欺骗了“efectively final”的要求。

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

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

共有1个答案

梅跃
2023-03-14

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

正如您已经知道的,对于并行流,这听起来很明显:需要这种限制,因为否则结果将是不确定性的。

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

你已经知道这一点,但下面是对其他读者的解释。从文件中:

流是懒惰的;源数据的计算仅在启动终端操作时执行,源元素仅在需要时使用。

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

当您调用终端操作(如 forEach()collect()count())时,就是计算发生的时候,按照先前构建的管道处理项目。

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

让您的流管道成为步骤X

我们希望并行处理我们的项目。因此,如果我们允许步骤Y的行为依赖于已经通过X的项目,那么Y是不确定的。这是因为在项目到达步骤Y的那一刻,已经通过X的项目集合在多次执行中不会相同(因为线程)。

根据定义,流用于处理流程中的项目。你可以把一个非并行流想象成这样:一个单独的项目通过所有的步骤,然后下一个项目通过所有的步骤,等等。事实上,医生说了一切:

流的元素在流的生命周期内仅访问一次。像迭代器一样,必须生成一个新的流来重新访问源的相同元素。

如果流不是这样工作的,那么在进入下一步之前,只对整个集合执行每一步也不会比这更好。这实际上允许在非并行流中使用可变参数,但可能会对性能产生影响(因为我们会在集合上迭代多次)。无论如何,他们目前的行为不允许你想要的。

 类似资料:
  • 如果我的API提供了一个流,客户端是否有办法修改基础集合? 例如: 客户端是否可以调用并以某种方式修改的内容?

  • 我正在寻找一种方法来调用多个参数方法,但是使用构造。文档中说只有在能够映射到功能接口时才可用。 基本上,如上所述,考虑使用中不同数量的属性的方法。

  • 只是在列表下面迭代 以上三个迭代有什么区别

  • 我正在解析输入JSON。对于一个字段,有3种可能: 字段不存在; 该值设置为NULL; 该值设置为有效值。 null

  • 5.7. 可变参数 参数数量可变的函数称为为可变参数函数。典型的例子就是fmt.Printf和类似函数。Printf首先接收一个的必备参数,之后接收任意个数的后续参数。 在声明可变参数函数时,需要在参数列表的最后一个参数类型之前加上省略符号“...”,这表示该函数会接收任意数量的该类型参数。 gopl.io/ch5/sum func sum(vals...int) int { total

  • 问题内容: 我正在尝试创建一个字符串扩展来做类似的事情 看起来像这样 它给我以下编译错误 类型CVaListPointer不符合协议CVargType 有人知道如何解决此编译错误吗? 问题答案: 这应该非常简单,只需更改您的参数,如下所示: 初始化(格式:语言环境:参数:)