我们应该如何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.Optional
types,它封装了一个值的存在/不存在,以及提供默认值的行为,或抛出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));