Java Collections.emptyList()而不是null检查?

Java Collections.emptyList()而不是null检查?,java,collections,null,empty-list,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)

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

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()真的很难看。。。我想知道是否有更好的方法来做这件事,甚至是一个完整的其他方式来处理这件事

以保存不必要的对象创建

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

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

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

if(list.equals(Collections.emptyList()))
但是如果
list==null
,仍然会抛出一个NullPointerException,所以它仍然不是您想要的

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


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

如果只在迭代中使用列表,则可以使用:
for(Object-Object:list)
,它对空列表没有任何作用,即没有一次迭代

否则,只需选中
list.isEmpty()

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++) {
     ;
}
private List=Collections.emptyList();
私有列表listForWrite(){
return list.isEmpty()?list=newarraylist():list;
}
添加无效(对象){
listForWrite().add(对象);
}
//避免每次都创建迭代器。
for(int i=0,size=list.size();i
您可以使用静态方法创建实用程序类,如:

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;
}
公共类ListUtil{
/**
*检查{@link List}是否为null或空。
*
*@param是泛型类型
*@param列出列表
*@return true,如果为null或空
*/
公共静态布尔值isNullOrEmpty(列表){
return list==null | | list.size()==0;
}
/**
*检查{@link List}是否不为null和空。
*
*@param是泛型类型
*@param列出列表
*@return true,如果不为null且为空
*/
公共静态布尔值isNotNullAndEmpty(列表){
返回列表!=null&&list.size()!=0;
}

}

我发现遵循这个惯例最容易:

  • 如果我的方法的目的是返回集合,那么该方法永远不会返回null。Null是不明确的。相反,如果使用番石榴,则返回
    Collection.emptyXXX()
    ImmutableXXX.of()

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


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

    以下是我在一些代码中使用的帮助器方法。在减少我在迭代列表之前通常必须进行的大量空检查方面,它确实非常有效。如果您想要一个不可变的列表,那么可以返回一个新的列表对象,而不是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;
    }
    
    如果list对象为null,那么helper方法将返回静态空列表,循环的内容将被跳过。这是一种很好的方法,可以避免创建包装任何列表迭代的空检查


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

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

    例如,类似这样的内容:

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

    这里有一个关于使用@Stas建议的可选集合的变体,但也使用了问题中最初要求的isEmpty immutable集合:

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

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

    List List=CollectionUtils.emptyIfNull(List);
    
    如果他坚持让
    null
    表示空集合就不会了。@aioobe你是对的,但是使用
    collections.emptyList()
    不会给你带来任何好处,不是吗?我想,但你不能将对象添加到集合中。emptyList(),因此签入add()…在这种情况下,您一定要始终使用
    new ArrayList()
    。@Philip然后使用
    new ArrayList()
    .isEmpty()
    。我认为您确实有一个很好的通用习惯用法,它就是“new ArrayList()”。这将是一种罕见的特殊情况,在这种情况下,它会占用您如此多的内存,这真的很重要。@aioobe说
    list.equals(Collections.emptyList())
    如果
    list==null
    ,则可能引发NullPointerException。那么您就不能执行
    Collections.emptyList().equals(list)
    吗?实际上,apache commons Collections已经有这样一个实用程序类:for (Object object : emptyIfNull(existingList)) { ... }
    public static List<String> addElement(List<String> list, String toAdd) {
           List<String> newList = Optional.ofNullable(list).orElse(new ArrayList<>());
           newList.add(toAdd);
           return newList;
    }
    
    public static List<String> addElement(List<String> list, String toAdd) {
       List<String> newList = Optional.ofNullable(list).orElse(Collections.emptyList());
       newList.add(toAdd);
       return newList;
    }
    
    public static List<String> addElement(List<String> list, String toAdd) {
       List<String> newList = Optional.ofNullable(list).orElse(Collections.emptyList());
       newList.add(toAdd);
       return newList;
    }
    
    // no need to indent everything inside a null check of myObjects
    for (MyObj myObj : Optional.ofNullable(myObjects).orElse(Collections.emptyList())){
        // do stuff with myObj
    }