Collections.emptyList()而不是null check?

时间:2011-07-01 10:40:21

标签: java collections null empty-list

如果我在一些可能多次实例化的类中有一个很少使用的集合,我有时可能会使用以下“成语”来保存不必要的对象创建:

List<Object> list = null;

void add(Object object) {
    if (list == null)
        list = new ArrayList<Object>();

    list.add(object);
}

// somewhere else
if (list != null)
    for (Object object : list)
         ;

现在我想知道我是否无法使用Collections.emptyList()消除这些空检查,但是我必须改变add()中的if检查,如下所示:

if (list == Collections.<Object>emptyList())
    list = new ArrayList<Object>();

除了每次只分配一个新的空集合外,还有更好的方法来处理这个问题吗?

编辑:为了清楚,我希望使用Collections.emptyList(),但上面检查add()真的很难看......我想知道是否有更好的方法来做到这一点,甚至是另一种处理这个问题的方式。

9 个答案:

答案 0 :(得分:17)

  

以节省不必要的对象创建

这是一个非常糟糕的想法,它将使用== null检查和其他处理极端情况来丢弃您的代码(并且可能最终会在空指针异常中结束)!

  

现在我想知道我是否无法使用Collections.emptyList() 消除这些空检查

不,不是真的。 emptyList()返回一个空列表。你可以

if (list.equals(Collections.<Object>emptyList()))

但如果list == null仍然会抛出NullPointerException,那么它仍然不是你所追求的。

我的建议:始终将列表初始化为new ArrayList<Object>,或者,如果您想要从方法返回空列表,请改用Collections.emptyList()。 (每次返回相同的实例,因此也不会创建不必要的对象。)

然后使用.isEmpty()检查集合是否为空。

答案 1 :(得分:9)

建议的答案是绝对正确的,只是小提示 - 在Java 8中,您可以使用新的Optional class来处理列表实例为空的情况,采用更实用的方法。

例如,像这样:

public static List<String> addElement(List<String> list, String toAdd) {
       List<String> newList = Optional.ofNullable(list).orElse(new ArrayList<>());
       newList.add(toAdd);
       return newList;
}

答案 2 :(得分:2)

emptyList()每次都不分配对象。

我会创建较少的包含List的对象,因此您可以每次创建列表。

你能做的是

private List<Object> list = Collections.emptyList();

private List<Object> listForWrite() {
    return list.isEmpty() ? list = new ArrayList<Object>() : list;
}


void add(Object object) {
    listForWrite().add(object);
}


// avoid creating an Iterator every time.
for (int i = 0, size = list.size(); i < size; i++) {
     ;
}

答案 3 :(得分:2)

这是我在一些代码中用于帮助方法的内容。真的可以很好地减少在迭代列表之前通常必须放置的大量空值检查。如果你想要一个不可变的列表,那么你可以返回一个新的列表对象而不是Collections.emptyList

/**
 * Helper method to return an empty list if provided one is null.
 *
 * @param list the list
 * @return the provided list or an empty one if it was null
 */
private static <T> List<T> emptyIfNull(List<T> list) {
    if (list == null) {
        return Collections.emptyList();
    }
    return list;
}

然后你只需使用辅助方法:

for (Object object : emptyIfNull(existingList)) { ... }

如果list对象为null,则helper方法将返回静态空列表,并且将跳过循环的内容。这是避免必须创建包装任何列表迭代的空检查的好方法。

我已经将列表的内部类型设置为Object类型,但是您显然将其更改为对您的使用最有意义的任何内容。

答案 4 :(得分:0)

如果你只使用列表进行迭代,你可以使用:for (Object object : list)这对空列表没有任何作用,即不是单次迭代。

否则,只需检查list.isEmpty()

答案 5 :(得分:0)

您可以使用静态方法创建实用程序类,例如:

public class ListUtil {

/**
 * Checks if {@link List} is null or empty.
 *
 * @param <E> the generic type
 * @param list the list
 * @return true, if is null or empty
 */
public static <E> boolean isNullOrEmpty(List<E> list) {
    return list == null || list.size() == 0;
}

/**
 * Checks if {@link List} is not null and empty.
 *
 * @param <E> the generic type
 * @param list the list
 * @return true, if is not null and empty
 */
public static <E> boolean isNotNullAndEmpty(List<E> list) {
    return list != null && list.size() != 0;
}

}

答案 6 :(得分:0)

我发现遵循这个惯例最简单:

  1. 如果我的方法的目的是返回一个Collection,那么该方法永远不会返回null。 Null含糊不清。相反,如果使用Guava,我会返回Collection.emptyXXX()ImmutableXXX.of()

  2. 如果我有一个将内部列表维护为成员的对象,请在构造函数中实例化它。我尽量不做懒惰的实例化,除非我能证明它是一个显着的增益,因为懒惰的代码,在我看来,在出现问题时往往更难以调试。

  3. 我真的看到不可变或不可修改的空集合是对象外部契约的一部分。如果你在内部使用集合,我只能看到使用不可变集合,如果你有充分的理由(并发性,一致性,对象的不变性)

答案 7 :(得分:0)

这里是使用@Stas建议的可选方法的变体,但也使用了问题中最初要求的isEmpty不可变集合:

public static List<String> addElement(List<String> list, String toAdd) {
   List<String> newList = Optional.ofNullable(list).orElse(Collections.emptyList());
   newList.add(toAdd);
   return newList;
}

这种方法也是我所能找到的最接近Javascript如果集合为null时使用空数组的好功能。

例如:

// no need to indent everything inside a null check of myObjects
for (MyObj myObj : Optional.ofNullable(myObjects).orElse(Collections.emptyList())){
    // do stuff with myObj
}

答案 8 :(得分:0)

emptyIfNull中有一个package org.apache.commons.collections4;方法。如果提供的为空,它将返回一个空列表。

List<Object> list = CollectionUtils.emptyIfNull(list);