一旦你从流中过滤了它们,就无法知道是否所有的余额都是(除非检查返回的内容,但这样你将无法使用流,因为它是一个终端操作)。null
count()
对数据进行两次传递可能是直接的解决方案,我可能会先这样做:
boolean allNulls = account.stream().map(Account::getBalance).allMatch(Objects::isNull);
Long sum = allNulls ? null : account.stream().map(Account::getBalance).filter(Objects::nonNull).mapToLong(l -> l).sum();
您可以使用 的解决方案摆脱过滤步骤,尽管可读性可能不是最好的:reduce
Long sum = account.stream()
.reduce(null, (l1, l2) -> l1 == null ? l2 :
l2 == null ? l1 : Long.valueOf(l1 + l2));
请注意该调用。这是为了避免条件表达式的类型是 ,因此在某些边缘情况下是 NPE。Long.valueOf
long
另一种解决方案是使用API。首先,从余额的值创建一个并减少它们:
Optional
Stream<Optional<Long>>
Optional<Long> opt = account.stream()
.map(Account::getBalance)
.flatMap(l -> Stream.of(Optional.ofNullable(l)))
.reduce(Optional.empty(),
(o1, o2) -> o1.isPresent() ? o1.map(l -> l + o2.orElse(0L)) : o2);
如果所有值都是 ,这将为你提供一个将为空的,否则它将为您提供非空值的总和。Optional<Long>
null
或者,您可能希望为此创建自定义收集器:
class SumIntoOptional {
private boolean allNull = true;
private long sum = 0L;
public SumIntoOptional() {}
public void add(Long value) {
if(value != null) {
allNull = false;
sum += value;
}
}
public void merge(SumIntoOptional other) {
if(!other.allNull) {
allNull = false;
sum += other.sum;
}
}
public OptionalLong getSum() {
return allNull ? OptionalLong.empty() : OptionalLong.of(sum);
}
}
然后:
OptionalLong opt = account.stream().map(Account::getBalance).collect(SumIntoOptional::new, SumIntoOptional::add, SumIntoOptional::merge).getSum();
如您所见,有多种方法可以实现这一目标,因此我的建议是:首先选择最具可读性的方法。如果解决方案出现性能问题,请检查是否可以改进(通过并行转动流或使用其他替代方法)。但是测量,不要猜测。