我们应该如何pipe理空值的jdk8stream

各位Java开发人员,

由于JDK8还没有发布,所以我知道这个主题可能会in advance一点(现在也不是这样了),但是我正在阅读一些关于Lambdaexpression式的文章,特别是与被称为Stream的新集合API相关的部分。

下面是Java杂志文章 (它是一个水獭种群algorithm)给出的例子:

 Set<Otter> otters = getOtters(); System.out.println(otters.stream() .filter(o -> !o.isWild()) .map(o -> o.getKeeper()) .filter(k -> k.isFemale()) .into(new ArrayList<>()) .size()); 

我的问题是,如果在Set内部迭代的中间发生了什么,其中一个otter是空的?

我会期望一个NullPointerException被抛出,但也许我仍然坚持以前的开发模式(非function),有人可以启发我如何处理?

如果这真的抛出一个NullPointerException,我觉得这个function相当危险,只能使用如下:

  • 开发人员确保没有空值(可能使用以前的.filter(o – > o!= null))
  • 开发者确保应用程序永远不会生成null otter或一个特殊的NullOtter对象来处理。

什么是最好的select,或者其他select?

谢谢!

目前的想法似乎是“容忍”空位,也就是允许他们在一般情况下,虽然有些行动宽容不够,最终可能会抛出NPE。 请参阅Lambda图书馆专家组邮件列表上的空值讨论 ,特别是此消息 。 随后出现了围绕选项#3的共识(Doug Lea提出了明显的反对意见)。 所以是的,OP对NPEpipe道的关注是有效的。

托尼·霍尔(Tony Hoare)把“空值”( nullll)称为“十亿美元的错误”并非没有任何意义。 处理空值是一个真正的痛苦。 即使是经典的collections(不考虑lambdas或stream)的空值是有问题的。 正如在评论中提到的那样,有些collections允许空值,而其他collections则不允许。 对于允许空值的集合,这会在API中引入歧义。 例如,使用Map.get() ,空返回表示密钥存在且其值为空,或者密钥不存在。 人们必须做额外的工作来消除这些情况。

null的通常用法是表示没有值。 处理Java SE 8提出的方法是引入一个新的java.util.Optionaltypes,它封装了一个值的存在/不存在,以及提供默认值的行为,或抛出exception,或者调用function等,如果价值是缺席的。 Optional只能由新的API使用,但系统中的其他所有内容仍然需要忍受空值的可能性。

我的build议是尽可能避免实际的空引用。 从这个例子中很难看出如何有一个“零”水獭。 但是如果有必要的话,OP的build议是过滤掉空值,或者将它们映射到一个哨兵对象( 空对象模式 )是很好的方法。

斯图亚特的答案提供了一个很好的解释,但我想提供另一个例子。

我试图在包含空值的Stream上执行reduce (实际上是LongStream.average() ,这是一种缩减typesLongStream.average() ,我遇到了这个问题。 由于average()返回OptionalDouble ,我认为Stream可以包含空值,但是抛出了NullPointerException。 这是由于斯图亚特对空虚空的解释 。

所以,如OP所示,我添加了一个像这样的filter:

 list.stream() .filter(o -> o != null) .reduce(..); 

或者像下面指出的那样,使用Java API提供的谓词:

 list.stream() .filter(Objects::nonNull) .reduce(..); 

从邮件列表讨论斯图尔特联系: 布赖恩·戈茨在河stream空值

虽然答案是100%正确的,但是一个小的build议来处理列表本身的null情况, 可选 :

  List<String> listOfStuffFiltered = Optional.ofNullable(listOfStuff) .orElseGet(Collections::emptyList) .stream() .filter(Objects::nonNull) .collect(Collectors.toList()); 

部分Optional.ofNullable(listOfStuff).orElseGet(Collections::emptyList)将允许您在listOfStuff为null时处理很好的情况,并返回一个emptyList而不是NullPointerExceptionexception。

如果您只想从stream中过滤空值,则可以简单地使用对java.util.Objects.nonNull(Object)的方法引用。 从它的文档:

此方法存在用作谓词 , filter(Objects::nonNull)

例如:

 List<String> list = Arrays.asList( null, "Foo", null, "Bar", null, null); list.stream() .filter( Objects::nonNull ) // <-- Filter out null values .forEach( System.out::println ); 

这将打印:

 Foo Bar 

一个例子如何避免null,例如在groupingBy之前使用filter

在groupingBy之前过滤掉null实例。

这是一个例子

 MyObjectlist.stream() .filter(p -> p.getSomeInstance() != null) .collect(Collectors.groupingBy(MyObject::getSomeInstance));