23

如果我在某个类中有一个很少使用的集合,可能会被多次实例化,我有时可能会求助于以下“成语”以节省不必要的对象创建:

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() 中的检查真的很丑……我想知道是否有更好的方法,甚至还有其他方法处理这个。

4

9 回答 9

22

为了节省不必要的对象创建

这是一个非常糟糕的主意,它会在你的代码中乱扔== null检查和其他处理极端情况(并且可能最终导致空指针异常)!

现在我想知道我是否不能使用Collections.emptyList()

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

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

但这仍然会抛出 NullPointerException if list == null,所以它仍然不是你所追求的。

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

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

于 2011-07-01T10:42:37.537 回答
19

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

例如,像这样:

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

按照评论中的提示,最好替换new ArrayList<>()Collections.emptyList()以防止创建空 ArrayList 的新实例

public static List<String> addElement(List<String> list, String toAdd) {
   List<String> newList = Optional.ofNullable(list).orElse(Collections.emptyList());
   newList.add(toAdd);
   return newList;
}
于 2016-08-30T06:53:48.183 回答
7

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

List<Object> list = CollectionUtils.emptyIfNull(list);
于 2019-12-17T14:03:58.110 回答
5

这是我在某些代码中用于辅助方法的方法。确实可以很好地减少我在迭代列表之前通常必须放置的大量空值检查。如果你想要一个不可变的列表,那么你可以返回一个新的列表对象而不是 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)) { ... }

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

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

于 2012-10-29T20:28:19.110 回答
2

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

我会创建更少的包含列表的对象,以便您每次都可以创建列表。

你能做的是

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++) {
     ;
}
于 2011-07-01T10:45:27.543 回答
2

这是使用 @Stas 建议的 optional 的变体,但也使用问题中最初要求的 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 中使用空数组的好功能的方法。

例如:

// no need to indent everything inside a null check of myObjects
for (MyObj myObj : Optional.ofNullable(myObjects).orElse(Collections.emptyList())){
    // do stuff with myObj
}
于 2019-02-26T15:51:09.040 回答
0

如果您只使用列表进行迭代,您可以只使用:for (Object object : list)它不会对空列表执行任何操作,即不是一次迭代。

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

于 2011-07-01T10:43:32.280 回答
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;
}

}

于 2011-07-01T10:45:31.857 回答
0

我发现最容易遵循这个约定:

  1. 如果我的方法的目的是返回一个集合,那么该方法永远不会返回 null。空是模棱两可的。相反,我返回Collection.emptyXXX()或者ImmutableXXX.of()如果使用番石榴。

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

我真的看到不可变或不可修改的空集合是对象外部合同的一部分。如果您在内部使用集合,那么只有在您有充分理由(对象的并发性、一致性、不变性)的情况下,我才能真正看到使用不可变集合

于 2012-09-14T14:42:47.527 回答