我们应该如何为空值管理jdk8流

时间:2013-06-13 07:00:44

标签: java null java-8 java-stream

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,我发现该功能非常危险,只能如下所示:

  • 开发人员确保没有空值(可能使用之前的 .filter(o - &gt; o!= null))
  • 开发人员确保永远不会申请 生成null otter或一个特殊的NullOtter对象来处理。

最佳选择或任何其他选项是什么?

谢谢!

5 个答案:

答案 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)的方法引用即可。从其文档:

  

此方法可用作Predicatefilter(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)

如何避免null的示例,例如在groupingBy

之前使用过滤器

在groupingBy之前过滤掉空实例。

这是一个例子

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