Java8过滤并返回如果只有元素

标签 java filter java-8 java-stream

如何使用java8流过滤列表并返回找到的元素,如果它是过滤列表中唯一的元素,否则(如果满足条件的元素更多,或者没有满足条件的结果)返回例如 Optional.empty()

我需要这样的东西:

假设我有一个:

List<String> list = Arrays.asList("Apple","Banana","Peach");

那我想要:

Optional<String> string = list.stream()
    .filter(item -> item.startsWith("A"))
    .findOne();

我知道我可以这样做:

boolean singleElement = list.stream()
        .filter(item -> item.startsWith("A"))
        .count() == 1;

String string = null;

if(singleElement){
  string = list.stream().filter(item -> item.startsWith("A")).iterator().next();
}

但我想知道是否可以在单个流中完成?

有没有单流解决方案?

最佳答案

不是很漂亮,但您可以将流limit 限制为 2 个元素,collect List 中的元素,然后查看该列表是否包含正好是一个元素。这仍然有不止一行,并且创建列表有一些开销,但该开销是有限的(对于大小为 2 的列表)并且它也不必迭代流两次。

List<String> tmp = list.stream()
    .filter(item -> item.startsWith("A"))
    .limit(2)
    .collect(Collectors.toList());
Optional<String> res = tmp.size() == 1 ? Optional.of(tmp.get(0)) : Optional.empty();

(我的另一个想法是在 limit(2) 之后使用 reduce((s1, s2) -> null) 并将任何两个匹配项减少到 null ,但不是返回一个 Optional.empty 这只会引发一个异常,即它确实工作,但也许这会触发一些更好(工作)的想法.)


更新:似乎 reduce 引发异常,Collectors.reducing 没有,而是根据需要返回 Optional.empty , 所以这也有效,如 this answer 所示一个非常相似的问题。尽管如此,我还是会添加 limit(2) 以使其提前停止:

Optional<String> res = list.stream()
    .filter(item -> item.startsWith("A"))
    .limit(2)
    .collect(Collectors.reducing((s1, s2) -> null));

(如果您喜欢最后一部分,请为原始答案投票。)

关于Java8过滤并返回如果只有元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49253241/

相关文章:

c# - 如何通过 ASP.NET 中的另一个下拉列表过滤下拉列表值,c#

java - 使用子对象列表更新主对象列表

java - java.lang.ArrayIndexOutOfBoundsException错误

java - JLabels 中的方法

Java 内部类和扩展

javascript - ng-repeat 中的 AngularJS 1 多个真/假过滤器

java - 在 Jasper 中显示 CLOB

javascript - 通过单值js过滤对象

java - 按两个标准排序以获得最终结果

java - lambda 表达式中变量名的约定是什么?