增强型for循环中的空值检查

211

如何在Java中防止for循环中的空值?

这种方式看起来很丑陋:

if (someList != null) {
    for (Object object : someList) {
        // do whatever
    }
}

或者

if (someList == null) {
    return; // Or throw ex
}
for (Object object : someList) {
    // do whatever
}

可能没有其他办法了。如果传入的是null,他们应该将其放在for循环本身中,这样就不会执行循环了吗?


2
你最好抛出一个 NPE(NullPointerException)。null 不等同于空集合。 - Tom Hawtin - tackline
6
@GregMattes 如何认为二月份的问题是十月份问题的重复? - Val
1
只需要使用Collections.nonNullElementsIn(...):http://stackoverflow.com/a/34913556/5637185 - Jeffrey Dilley
11个回答

255

你最好确认一下你从哪里获取了那个列表。

只需要一个空列表,因为一个空列表不会失败。

如果你从其他地方获取这个列表并且不确定它是否可行,你可以创建一个实用方法并像这样使用它:

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

当然,safe也是安全的:

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

64
请注意,使用Collections.emptyList()可以避免分配额外的对象(如果我没记错的话)。 - Jon Skeet
8
@Jon: 我一直在想,那个emptyList有什么用途 http://java.sun.com/j2se/1.5.0/docs/api/java/util/Collections.html#emptyList()。IIRC是什么意思? - OscarRyz
14
IIRC = "如果我记得正确的话"。是的,对于所有调用Collections.emptyList(),都会返回单例实例。 - ColinD
3
@ChristopherWirt 因为它回答了问题 :D - Tarik
1
Collections.emptyListCollections.EMPTY_LIST都返回public static final List EMPTY_LIST = new EmptyList<Object>(); - sdc
显示剩余6条评论

106

如果你传入null,你可以编写一个帮助方法,该方法可能会返回一个空序列:

public static <T> Iterable<T> emptyIfNull(Iterable<T> iterable) {
    return iterable == null ? Collections.<T>emptyList() : iterable;
}
然后使用:
for (Object object : emptyIfNull(someList)) {
}

虽然我认为我不会这样做 - 我通常会使用你的第二种形式。特别是,“or throw ex”很重要 - 如果它确实不应该为空,你一定要抛出异常。你知道有什么出了问题,但你不知道损坏的程度。早期终止。


3
我会将参数中的“list”改为“iterable”,因为并非所有迭代器都是列表。 - Lombo
使用此方法时要小心:由于使用了Collections类,因此使用此方法涉及到您的列表必须是不可变的。 - Tanorix
@tanorix:以什么方式? - Jon Skeet
@JonSkeet,您可以看到Collections类的emptyList()返回一个不可变列表:https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#emptyList--因此,如果用户不想让他的列表成为不可变的,这可能会有问题。 - Tanorix
@tanorix:但这个问题的重点在于对返回值进行迭代。这不会修改它。这就是为什么emptyIfNull的返回类型是Iterable<T> - Iterator<T>上有不幸的remove方法,但那是唯一可变的方面(如果你有一个空集合,为什么要尝试从中删除任何内容?)。不清楚你在这里反对什么。 - Jon Skeet

41

已经到了2017年,现在您可以使用 Apache Commons Collections4

使用方法:

for(Object obj : ListUtils.emptyIfNull(list1)){
    // Do your stuff
}

您可以使用 CollectionUtils.emptyIfNull 对其他集合类进行相同的空值检查。


2
虽然可以工作,但会创建不必要的列表对象。使用CollectionUtils.ifNotEmpty可能更冗长,但更高效和更快。尽管这并不重要... - Lawrence
2
在2017年,我期望List.emptyIfNull(list1)。 - Dima
5
@Lawrence,这种方法不会创建新的列表对象,而是在内部使用了Collections.emptyList(),它始终返回相同的预先分配的空的不可修改列表。 - Yoory N.
如果您调用 myobject.getCompanies().getAddresses(),并且两者都返回一个List,同时两个值都可能为null,该怎么办? - powder366

14

使用Java 8的Optional

for (Object object : Optional.ofNullable(someList).orElse(Collections.emptyList())) {
    // do whatever
}

2
它比简单的三元运算符更冗长,例如 someList != null ? someList : Collections.emptyList(),并且创建并立即丢弃 Optional 对象的实例。 - Yoory N.
7
这些“怪兽行”比一个简单的if(someList == null)语句更优雅。让我们用一行代码编写银行应用程序... - Andreas Panagiotidis

13

使用 commons-lang 库中的 ArrayUtils.nullToEmpty 方法来处理数组。

for( Object o : ArrayUtils.nullToEmpty(list) ) {
   // do whatever 
}

这个功能存在于commons-lang库中,该库包含在大多数Java项目中。

// ArrayUtils.nullToEmpty source code 
public static Object[] nullToEmpty(final Object[] array) {
    if (isEmpty(array)) {
        return EMPTY_OBJECT_ARRAY;
    }
    return array;
}

// ArrayUtils.isEmpty source code
public static boolean isEmpty(final Object[] array) {
    return array == null || array.length == 0;
}

这与@OscarRyz给出的答案相同,但为了DRY原则,我认为值得注意。请参见commons-lang项目页面。这里是nullToEmpty API 文档源代码
如果您的项目中尚未包含commons-lang,请在Maven中添加以下条目。
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.4</version>
</dependency>

不幸的是,commons-lang没有为List类型提供此功能。在这种情况下,您必须像之前提到的那样使用帮助方法。

public static <E> List<E> nullToEmpty(List<E> list)
{
    if(list == null || list.isEmpty())
    {
        return Collections.emptyList();
    }
    return list;
}

8
如果你从实现的方法调用中获取了那个 List,那么不要返回 null,而是返回一个空的 List
如果你无法更改实现,则只能使用 null 检查。如果它不应该是 null,那么抛出异常。
我不会选择返回一个空列表的辅助方法,因为它可能有时很有用,但这样你就会习惯于在每个循环中调用它,可能会隐藏一些错误。

4
我已经修改了上面的回答,所以您不需要从Object进行转换。
public static <T> List<T> safeClient( List<T> other ) {
            return other == null ? Collections.EMPTY_LIST : other;
}

然后只需通过调用列表即可。
for (MyOwnObject ownObject : safeClient(someList)) {
    // do whatever
}

解释: MyOwnObject: 如果是 List<Integer>,则此情况下 MyOwnObject 将是 Integer。


3

如果您不想编写自己的静态空安全方法,可以使用commons-lang的org.apache.commons.lang.ObjectUtils.defaultIfNull(Object, Object)。例如:

    for (final String item : 
    (List<String>)ObjectUtils.defaultIfNull(items, Collections.emptyList())) { ... }

ObjectUtils.defaultIfNull JavaDoc


对我来说,这个答案是最优雅的。 - Truong Nguyen
另一种类似的方法是使用Java的本地Objects类,即Objects.requireNonNullElse(itemsList, new ArrayList<String>()) - Karthik Rao

1
另一种有效地防止for循环中出现null的方法是使用Google Guava的Optional<T>来包装您的集合。这样做的目的是希望清晰地表明可能存在一个有效空集合,因为客户端应该使用Optional.isPresent()检查集合是否存在。

0

使用CollectionUtils.isEmpty(Collection coll)方法。它是一个空值安全检查指定的集合是否为空。

对应的Java包为:import org.apache.commons.collections.CollectionUtils

Maven依赖:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.0</version>
</dependency>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接