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

根据哪个过滤器从流中过滤了最后一个元素,反应不同

长孙作人
2023-03-14

我尝试根据过滤最后一个元素的过滤器引发异常:

// Find the first person who is older than 18 and has a pet
Person firstOlderThan18AndWithPet =  this.people.entrySet().stream()
    .map(e -> e.getValue())
    .filter(e -> e.getAge() >= 18)
    .findAtLeastOne() // <-- this method doesn't exist
    .orElseThrow(AgeException::new) // <-- exception because no person was older than 18
    .filter(e -> e.hasPet())
    .findFirst()
    .orElseThrow(NoPetException::new); // <-- exception because no person older than 18 has a pet

这样我就可以分辨出为什么在人流中没有发现任何人。是因为年龄还是因为没有人养宠物。

我只看到一个选项,并用两个流来实现它?

List<Person> peopleOlderThan18 = this.people.entrySet().stream()
    .map(e -> e.getValue())
    .filter(e -> e.getAge() >= 18)
    .collect(Collectors.toList());

if (0 == peopleOlderThan18.size()) {
    throw new AgeException();
}

Person firstOlderThan18AndWithPet = peopleOlderThan18.stream()
    .filter(e -> e.hasPet())
    .findFirst()
    .orElseThrow(NoPetException::new); // <-- exception because no person older than 18 has a pet

或者我能做些什么来把所有的事情都集中在一个流里?

共有3个答案

皮煜
2023-03-14

我现在想出了一个解决方案,在这个解决方案中,我可以抛出正确的异常,而不会在中间留下流。我使用的解决方案如下所示:

AtomicBoolean ageMatchedAtLeastOnce = new AtomicBoolean(false);

// Find the first person who is older than 18 and has a pet
Person firstOlderThan18AndWithPet =  this.people.entrySet().stream()
    .map(e -> e.getValue())
    .filter(e -> {
        var ageMatch = e.getAge() >= 18
     
        if (ageMatch) {
            ageMatchedAtLeastOnce.set(true);
        }

        return ageMatch;
    })
    .filter(e -> e.hasPet())
    .findFirst()
    .orElseThrow(() -> !ageMatchedAtLeastOnce.get() ? new AgeException() : new NoPetException());

我不知道这是不是一个好的解决方案。很高兴在评论中听到你的意见。

荀振国
2023-03-14

无法克隆/分叉流。您可以组合一系列运算符,并只应用一次。因此,其中一种方法是利用元组存储中间结果(Java中没有元组文本)。为了在不损失代码表达能力的情况下保留流的优点,您可以提取公共部分并重新初始化流以应用另一组运算符。

    Predicate<Person> olderThan18 = person -> person.age >= 18;

    Person firstOlderThan18 = people.stream()
      .filter(olderThan18)
      .findFirst()
      .orElseThrow(Exception::new);

    Person firstOlderThan18AndWithPet = people.stream()
      .filter(olderThan18)
      .filter(person -> person.hasPet)
      .findFirst()
      .orElseThrow(AssertionError::new);

https://replit.com/join/rxbbvwoudq-redneckz

於永寿
2023-03-14

您必须决定要针对哪种情况进行优化。

通常,我们针对无错误情况进行优化。因此,我们可以乐观地尝试在单个迭代中找到匹配元素,而无需额外存储:

Person firstOlderThan18AndWithPet =  this.people.values().stream()
    .filter(e -> e.getAge() >= 18 && e.hasPet())
    .findFirst()
    .orElseThrow(() ->
        this.people.values().stream().nonMatch(e -> e.getAge() >= 18)?
        new AgeException():
        new NoPetException()
    );

只有在未找到匹配项且第二次迭代短路时,才会执行第二次迭代。在这个错误的案例中,一旦我们遇到18岁以上的人,我们就知道问题是没有候选人有宠物。

我们可以尝试避免第二次迭代,但这会使代码更加复杂,而只有例外情况才会受益,代价是非错误情况。

 类似资料:
  • 问题内容: 我有一个过滤器linkifyStuff,其中需要使用其他过滤器处理一些变量。我无法弄清楚从另一个调用一个过滤器的语法。 我了解过滤器链接-这不是我想要的。我想将过滤器应用于linkifyStuff过滤器中的局部变量,而不是其输入或输出。 我希望像下面这样工作,但是$ filter(’filtername’)显然不是正确的语法。 我可以为sanitizeStuff和sanitizeStu

  • 问题内容: 我有一个BLoC,它使用原始输入(产生JSON对象列表)并将其转换为使用的可用对象。UI将显示该列表。用户可以应用过滤器(本身就是流到BLoC中的流),以便BLoC用相应的语句更新输入流转换器。 问题是:当过滤器更改时,UI不会更新,因为输出流取决于JSON输入流(而不是过滤器流)的事件。我的假设是,我需要创建自己的流,将输入事件和过滤器事件都转发到该流中,或者我需要在转换后的输入流上

  • 如果我有一个<代码>流 最明显的解决方案是使用<code>limit(originalLength-elementsToRemoveAtEnd),但这需要事先知道初始长度,这并不总是如此。 有没有一种方法可以删除长度未知的流的最后几个元素,而无需将其收集到中,计算元素并再次流式传输?

  • 我想要找到合适的正则表达式匹配的行数。输入是通过Java Stream插入的日志文件。我想对这个流应用多个过滤器,但每隔一段时间计算一次。

  • null 或用java

  • 问题内容: 我想删除原始数组(是)中的特定元素。我那个数组,并返回新的数组。但这不会影响此代码中的原始数组。我如何轻松地从原始数组中删除那些元素? 问题答案: 该方法不仅用于收集元素集,而且还用于收集元素集。如果您想通过评估条件来获得一项,那么您还有其他三种选择。,并因此只有当你想对多个项目的操作,你应该考虑使用过滤功能。就需要完成的工作而言,没有一个答案是完整的。他们使用过滤器功能隔离一个集合(