避免在“for”语句中出现空指针异常

时间:2014-04-08 09:07:17

标签: java collections arraylist

在我的代码中,当NullPointerException为null时,我通常使用这种方法来避免List in语句:

if (myList != null && myList.size() > 0) {
    for ( MyObj obj : myList ) {
        System.out.println("MyObjStr: "+obj);
    }
}

是否有其他方法可以在不写“if”语句的情况下执行相同操作,但使用相同的“for”语句?

6 个答案:

答案 0 :(得分:11)

不需要检查尺寸。如果列表中没有对象,则不会执行for循环。

只有在您不确定对象的状态时,才需要检查null。但是当使用你自己的对象时(例如,没有通过争论从外部给出),那么就不需要进行空检查。

请参阅Avoiding “!= null” statements in Java?,了解为什么没有经验的开发人员通常会使用空检查进行分解。

答案 1 :(得分:4)

你不想只是"避免NPE"。 NPE是一种注意编程错误的好方法,因此您必须小心需要进行空检查的内容。许多程序员在防御性的地方进行无效检查,因为他们不再信任API合同。

  • 如果您的NPE中包含无理由为的内容,那么您之前就做错了(这是因为您的集合未初始化)。你不想隐藏它,你希望它在你脸上爆炸,所以你可以立即修复它(快速原则)。

  • 如果 null是变量的可能(且有意义的)值(或者如果值来自外部源),则需要对其进行空值检查。但是,您必须处理此案例,不要只是跳过生成NPE的代码。如果你只是跳过它,那么后来的代码就不比当前的代码更安全,并且对于同一个变量将再次需要进行空检查。

@ifLoop提供了一个关于这个主题的另一篇文章的非常好的链接,所以我在这里复制它,因为我的答案被接受了: Avoiding “!= null” statements in Java?

附注:循环不需要进行尺寸检查。如果集合为空,则只会跳过循环。

答案 2 :(得分:2)

这是一种优雅的方式,可以在similar post中找到。使用

for( Object o : safe( list ) ) {
   // do whatever 
 }

public static List safe( List other ) {
    return other == null ? Collections.EMPTY_LIST : other;
}

有人说,让你的方法返回空数组而不是null是一个好习惯。例如,您可以返回

return Collections.EMPTY_LIST;

在每个catch块中。

通过这种方式,您可以安全地循环使用它们,当您获得NPE时,您就会知道代码而不是数据有问题。在这方面,正如@Joffrey所说,NPE将非常受欢迎

答案 3 :(得分:1)

嗯,你可以做到一行,但有可读性损失:

for ( MyObj obj : (myList == null ? new ArrayList<MyObj>() : myList) ) {
    System.out.println("MyObjStr: "+obj);
}

答案 4 :(得分:0)

还有另一种避免将NULL传递到for(forEach)循环的可能性-我们之前可以使用 CollectionUtils 库中的 isNotEmpty(Collection coll)方法。

示例:

if (CollectionUtils.isNotEmpty(someCollection)) {
    for (Item item: someCollection) {
    ...
    }
}

或:

if (CollectionUtils.isNotEmpty(someCollection)) {
    someCollection.forEach(...);
}

答案 5 :(得分:0)

在很多情况下,您应该进行将DTO传入另一个对象的映射练习。发送空集合而不是null可能会浪费流量,甚至通过使用排除null mapper.setSerializationInclusion(Include.NON_NULL);甚至mapper.setSerializationInclusion(Include.NON_EMPTY);

也就是说,如果您需要执行以下操作:

Collection<Dto> dtos = null;
for(Dto dto: dtos) {
   //doSomething
} 

您必须使用if保护(好的,但是我更喜欢另一种方式),或者坚持使用NullObject习惯用法(好):

Collection<Dto> safeDtos = Optional.ofNullable(dtos).orElse(Collections.emptyList());
for(Dto dto: safeDtos) {
   //doSomething
} 

相同,但对于流:

Optional.ofNullable(dtos).orElse(Collections.emptyList()).stream()
    .map(this::doSomething)
    .collect(Collectors.toList());

此外,除了进行映射操作外,请不要泄漏任何下游代码中的DTO。在DTO和其余代码之间,应该有一个保护边界。

DTO->映射->域对象(或另一个保存NPE的中间对象,也许有枚举而不是字符串等)->代码的其余部分。