如果我在一些可能多次实例化的类中有一个很少使用的集合,我有时可能会使用以下“成语”来保存不必要的对象创建:
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()真的很难看......我想知道是否有更好的方法来做到这一点,甚至是另一种处理这个问题的方式。
答案 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)
我发现遵循这个惯例最简单:
如果我的方法的目的是返回一个Collection,那么该方法永远不会返回null。 Null含糊不清。相反,如果使用Guava,我会返回Collection.emptyXXX()
或ImmutableXXX.of()
。
如果我有一个将内部列表维护为成员的对象,请在构造函数中实例化它。我尽量不做懒惰的实例化,除非我能证明它是一个显着的增益,因为懒惰的代码,在我看来,在出现问题时往往更难以调试。
我真的看到不可变或不可修改的空集合是对象外部契约的一部分。如果你在内部使用集合,我只能看到使用不可变集合,如果你有充分的理由(并发性,一致性,对象的不变性)
答案 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);