我有一个我希望减少的枚举值流。如果流为空或包含不同的值,我想要null
。如果它只包含单个值的(多个实例),我想要该值。
[] null
[A, B, A] null
[A] A
[A, A, A] A
我尝试使用reduce:
return <lots of filtering, mapping, and other stream stuff>
.reduce((enum1, enum2) -> enum1 == enum2 ? enum1 : null)
.orElse(null);
不幸的是,这不起作用,因为当结果为NullPointerException
时,此reduce方法会抛出null
。有谁知道为什么会这样?为什么null
不是有效的结果?
现在,我解决了这个问题:
MyEnum[] array = <lots of filtering, mapping, and other stream stuff>
.distinct()
.toArray(MyEnum[]::new);
return array.length == 1 ? array[0] : null;
虽然这有效,但我对此并不满意&#34;绕行&#34;。我喜欢reduce,因为它似乎是合适的,并将所有内容放在一个流中。
任何人都可以考虑使用reduce的替代方法(理想情况下代码不是太多)吗?
答案 0 :(得分:1)
通常,返回Optional
的所有Stream方法都不允许null
值,因为无法区分null
结果和“无结果”(空流)。
你可以使用占位符值解决这个问题,不幸的是,这需要暂停类型安全性(因为枚举集之外没有类型兼容的值):
return <lots of filtering, mapping, and other stream stuff>
.reduce((enum1, enum2) -> enum1 == enum2? enum1: "")
.map(r -> r==""? null: (MyEnum)r)
.orElse(null);
如果映射函数返回Optional.map
, null
将返回一个空的可选项,因此在该步骤之后,无法再区分空流和null
结果{{1在这两种情况下都会返回orElse(null)
。
但也许数组绕道只觉得不满意,因为阵列不是中间结果的最佳选择? <怎么样
null
如果EnumSet<MyEnum> set = <lots of filtering, mapping, and other stream stuff>
.collect(Collectors.toCollection(() -> EnumSet.noneOf(MyEnum.class)));
return set.size()==1? set.iterator().next(): null;
类型的常量不超过64,EnumSet
只是一个bitset,一个long
值。这比数组要便宜得多,因为enum
自然是不同的,所以不需要对流进行Set
操作,这会在引擎盖下创建distinct()
。
答案 1 :(得分:0)
大多数流高阶函数不允许null
作为参数或函数返回值。他们要阻止另一个billion-dollar mistake。这样的回复记录在案here:
可选reduce(BinaryOperator累加器)
.....
抛出: NullPointerException - 如果减少的结果为null
答案 2 :(得分:0)
真正的数学方法怎么样(难以维持,我同意)?
Arrays.stream(array).map(e -> e.ordinal() + 1).reduce(Integer::sum)
.map(i -> (double) i / array.length == array[0].ordinal() + 1 ? array[0] : null)
.orElse(null)