Hello Java开发人员,
我知道主题可能有点in advance
因为JDK8还没有发布(现在还没有发布..)但我正在阅读一些关于Lambda表达式的文章,特别是与新的相关的部分集合API称为Stream。
以下是Java Magazine article中给出的示例(它是一种水獭种群算法..):
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为null会发生什么?
我希望抛出NullPointerException但是我可能仍然停留在以前的开发范例(非功能性)中,有人可以告诉我应该如何处理它吗?
如果这确实抛出了NullPointerException,我发现该功能非常危险,只能如下所示:
最佳选择或任何其他选项是什么?
谢谢!
答案 0 :(得分:63)
尝试在包含空值的Stream上执行reduce
时遇到此问题(实际上它是LongStream.average()
,这是一种减少类型)。由于average()返回OptionalDouble
,我假设Stream可以包含空值,但抛出了NullPointerException。这是由于Stuart's explanation为null v。空。
所以,正如OP建议的那样,我添加了一个类似的过滤器:
list.stream()
.filter(o -> o != null)
.reduce(..);
或者正如Tangens在下面指出的那样,使用Java API提供的谓词:
list.stream()
.filter(Objects::nonNull)
.reduce(..);
从邮件列表讨论Stuart链接: Brian Goetz on nulls in Streams
答案 1 :(得分:62)
虽然答案是100%正确的,但建议使用Optional来改善null
列表本身的 List<String> listOfStuffFiltered = Optional.ofNullable(listOfStuff)
.orElseGet(Collections::emptyList)
.stream()
.filter(Objects::nonNull)
.collect(Collectors.toList());
案例处理:
Optional.ofNullable(listOfStuff).orElseGet(Collections::emptyList)
部分listOfStuff
将允许您在Add the hours --> DATEADD(hh,LEFT(HORA_FINAL,2),DATA)
Add the minutes --> DATEADD(n,RIGHT(HORA_FINAL,2),DATA)
为空时很好地处理该情况,并返回空列表而不是使用NullPointerException失败。
答案 2 :(得分:39)
目前的想法似乎是“容忍”空值,即一般情况下允许它们,尽管某些操作不那么容忍并且最终可能会抛出NPE。请参阅Lambda Libraries专家组邮件列表中的discussion of nulls,特别是this message。随后出现了关于选项#3的共识(Doug Lea的一个值得注意的反对意见)。因此,OP对NPE管道爆炸的担忧是有效的。
Tony Hoare提到空值并不是因为"Billion Dollar Mistake."处理空值是一种真正的痛苦。即使使用经典集合(不考虑lambdas或流),空值也是有问题的。正如评论中提到的fge一样,某些集合允许空值而其他集合则不允许。对于允许空值的集合,这会在API中引入歧义。例如,对于Map.get(),null返回表示密钥存在且其值为null,或者密钥不存在。人们必须做额外的工作来消除这些案件的歧义。
null的通常用法是表示没有值。处理Java SE 8的方法是引入一种新的java.util.Optional
类型,它封装了值的存在/不存在,以及提供默认值,抛出异常或调用异常的行为。功能等,如果值不存在。 Optional
仅由新API使用,但系统中的其他所有内容仍然需要提供空值。
我的建议是尽可能避免实际的空引用。鉴于可能存在“无效”水獭的例子,很难从这个例子中看出来。但如果有必要,OP建议过滤掉空值,或将它们映射到一个标记对象(Null Object Pattern)是很好的方法。
答案 3 :(得分:18)
如果您只想从流中过滤空值,则只需使用java.util.Objects.nonNull(Object)的方法引用即可。从其文档:
此方法可用作Predicate,
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
答案 4 :(得分:7)
在groupingBy之前过滤掉空实例。
这是一个例子
MyObjectlist.stream()
.filter(p -> p.getSomeInstance() != null)
.collect(Collectors.groupingBy(MyObject::getSomeInstance));