如何用Java Stream过滤列表,无匹配项时返回null而非空列表?
优雅实现Java Stream过滤后返回null(无符合元素时)
嘿,这个需求挺常见的!JDK原生的Collectors确实没有直接提供toListOrNullIfEmpty()这种方法,但我们有几种更简洁的方式来实现你的需求,不用每次都写冗余的判空if语句:
1. 自定义可复用的Collector
这是最优雅的方案,把逻辑封装成一个自定义收集器,以后可以随时复用:
public static <T> Collector<T, ?, List<T>> toListOrNullIfEmpty() { return Collector.of( ArrayList::new, List::add, (left, right) -> { left.addAll(right); return left; }, list -> list.isEmpty() ? null : list ); }
使用的时候就像用原生收集器一样简单:
List<MyObj> nullableList = myObjs.stream() .filter(m -> m.isFit()) .collect(toListOrNullIfEmpty());
这个收集器的逻辑很清晰:用ArrayList收集元素,最后在finisher阶段判断列表是否为空,空则返回null,否则返回收集到的列表。
2. 用Optional简化现有逻辑
如果不想自定义收集器,也可以用Optional来压缩你的现有代码,让它更紧凑:
List<MyObj> nullableList = Optional.of(myObjs.stream() .filter(m -> m.isFit()) .collect(Collectors.toList())) .filter(list -> !list.isEmpty()) .orElse(null);
这里利用Optional的filter方法判断列表是否非空,orElse(null)在空的时候返回null。因为Collectors.toList()永远不会返回null,所以用Optional.of()比ofNullable()更安全。
3. 用Stream的reduce(仅作思路拓展,不推荐)
还有一种用reduce的方式,但可读性不如前两种,仅作参考:
List<MyObj> nullableList = myObjs.stream() .filter(m -> m.isFit()) .reduce(new ArrayList<>(), (list, item) -> { list.add(item); return list; }, (list1, list2) -> { list1.addAll(list2); return list1; }); nullableList = nullableList.isEmpty() ? null : nullableList;
这种写法其实和你原来的逻辑差不多,只是把收集过程用reduce实现了,并没有更简洁,所以还是前两种方案更好。
总结一下:如果需要多次使用这个逻辑,自定义Collector是最优解;如果只是偶尔用一次,用Optional的写法就足够简洁了。
内容的提问来源于stack exchange,提问作者Gavriel
相关产品推荐
相关产品推荐

