根据过滤流中最后一个元素的过滤器的不同,做出不同的React

ou6hu8tu  于 2021-08-20  发布在  Java
关注(0)|答案(3)|浏览(297)

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

// 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

或者我可以做些什么,在一条流中完成所有事情?

t5fffqht

t5fffqht1#

无法克隆/分叉流。您可以组合一系列运算符,并仅应用一次。因此,其中一种方法是利用元组存储中间结果(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

laik7k3q

laik7k3q2#

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

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岁的人,我们就知道问题是没有候选人有宠物。
我们可以尝试避免第二次迭代,但这会使代码更加复杂,而只有例外情况才会受益,代价是非错误情况。

fruv7luv

fruv7luv3#

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

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;
    })
    .findAtLeastOne() // <-- this method doesn't exist
    .orElseThrow() // <-- exception because no person was older than 18
    .filter(e -> e.hasPet())
    .findFirst()
    .orElseThrow(() -> !ageMatchedAtLeastOnce.get() ? new AgeException() : new NoPetException());

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

相关问题