在Java中优先考虑流过滤器功能

时间:2017-04-21 21:07:48

标签: java java-8 java-stream

我正在寻找一个过滤流内容但使用优先级的选项。

以下是伪代码:

results.stream().filter(prio1).ifNotFound(filter(prio2)).collect(toList())

结果列表应按照名为" prio1"的第一个标准进行过滤。如果找不到匹配项,则应使用第二个过滤器尝试过滤第二个标准prio2,然后收集结果

如何使用流在Java 8中实现此目的?

我正在寻找一个单行流。

3 个答案:

答案 0 :(得分:4)

另一种不使用anyMatch的方法,而是在对结果进行操作之前对条目进行分组。

Optional.of(results.stream()
                   .filter(prio1.or(prio2))
                   .collect(Collectors.groupingBy(prio1::test)))
        .map(map -> map.getOrDefault(true, map.get(false)))
        .ifPresent(System.out::println);

我使用了Optional,因此你有一个&#34;一个班轮&#34; (只是格式化它,以便它更具可读性)。您也可以使用ifPresent而不是orElseGet(Collections::emptyList),而将结果保存到List<String>

groupingByprio1prio1个过滤条目中的所有prio2个匹配条目放入密钥true和其余prio2 - 匹配false条目。如果我们没有true中的任何条目,那么prio2 - 已过滤的条目将作为默认值返回。如果没有任何prio1prio2匹配结果,则不会发生任何事情。

请注意,如果您直接返回Map,那么如果您的过滤器是互斥的,则只有prio2中的所有false个匹配条目。

答案 1 :(得分:3)

您需要stream()两次您的搜索结果,但以下内容应该作为一行:

results.stream().filter(results.stream().anyMatch(prio1) ? prio1 : prio2).collect(Collectors.toList());

(感谢flakes首先使用类似的策略发布多个班轮。)

编辑:由于一些出色的新答案已经曝光,我想我会对这种多流/ anyMatch策略进行简短的辩护,并参考其中的某些其他部分螺纹:

  • As pointed out by eckesanyMatch已经过优化,可以提前返回,从而花费最少的时间来阅读额外的流(特别是在prio1可能匹配的情况下)。事实上,anyMatch只会在后备(prio2)情况下读取整个流,因此对于平均运行,您只是迭代一个和一个分数列表长度。

  • 在每种情况下,使用Collectors.groupingBy(...)方法构造一个Map和两个Lists,而上面的方法最多只创建一个List。随着results的大小增加,这里的内存开销差异将变得非常显着。分组是针对整个流完成的,因此即使第一个元素恰好通过prio1,也必须针对prio1.or(prio2) 检查每个元素,然后针对{{1>检查再一次。

  • prio1未考虑groupingByprio1不相互排斥的情况。如果prio2可以为通过prio2.test(e)的某些true返回e,那么这些元素将在后备prio1列表中丢失。一次使用prio2和一个过滤器可以避免此问题。

  • 上述方法的行长和复杂性对我来说似乎更容易管理。

答案 2 :(得分:2)

只是提出一个条件:

final List<Foo> foo;
if (results.stream().anyMatch(prio1)) {
    foo = results.stream().filter(prio1).collect(Collectors.toList());
} else {
    foo = results.stream().filter(prio2).collect(Collectors.toList());
}

如果你真的想要一个单行,那么你可以做以下事情,但是没有办法绕过两次列表。我认为if/else版本更清晰,更易于维护。

final List<Foo> foo = results.stream()
    .filter(results.stream().anyMatch(prio1)? prio1 : prio2)
    .collect(Collectors.toList());
相关问题