Collections.emptyList() вместо нулевой проверки?
Если у меня есть редко используемая коллекция в каком-то классе, которая может быть создана несколько раз, я иногда могу прибегнуть к следующей "идиоме", чтобы сохранить ненужные создания объектов:
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()
, но тогда мне пришлось бы изменить if if check in add()
следующим образом:
if (list == Collections.<Object>emptyList())
list = new ArrayList<Object>();
Есть ли лучший способ справиться с этим, кроме как просто выделять новую пустую коллекцию каждый раз?
EDIT:, чтобы быть ясным, я хотел бы использовать Collections.emptyList(), но вышеуказанная проверка в add() действительно очень уродливая... Мне было интересно, если там лучше способ сделать это или даже совсем другой способ справиться с этим.
Ответы
Ответ 1
, чтобы сохранить ненужные создания объектов
Это действительно плохая идея, которая поместит ваш код с помощью проверок == null
и другой обработки угловых случаев (и, предположительно, заканчивается исключениями с нулевым указателем)!
Теперь мне было интересно, не могу ли я устранить эти нулевые проверки, используя Collections.emptyList()
Нет, не совсем. emptyList()
возвращает пустой список. Вы могли бы сделать
if (list.equals(Collections.<Object>emptyList()))
но это все равно вызовет исключение NullPointerException, если list == null
, поэтому он все равно не то, что вам нужно.
Моя рекомендация: всегда инициализируйте список до new ArrayList<Object>
или, если вы хотите вернуть пустой список из метода, используйте Collections.emptyList()
. (Это возвращает один и тот же экземпляр каждый раз, поэтому нет ненужного создания объекта.)
И затем используйте .isEmpty()
, чтобы проверить, пуста ли коллекция или нет.
Ответ 2
Предлагаемый ответ абсолютно верный, просто небольшой совет - в 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;
}
Ответ 3
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++) {
;
}
Ответ 4
Вот что я использую для вспомогательного метода в некоторых моих кодах. На самом деле прекрасно работает в уменьшении тонны нулевых проверок, которые я обычно должен разместить перед повторением списков. Если вам нужен список, который не был бы неизменным, вы можете вернуть новый объект списка вместо 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)) { ... }
Если объект списка имеет значение null, то вспомогательный метод возвращает статический пустой список, и содержимое вашего цикла будет пропущено. Это хороший способ избежать создания нулевых проверок, обертывающих любые итерации списка.
Я сделал внутренности списка типа Object только для примера, но вы, очевидно, изменили бы это на то, что имеет смысл для вашего использования.
Ответ 5
Если вы используете только список для итераций, вы можете просто использовать: for (Object object : list)
, который ничего не сделал бы для пустых списков, т.е. ни одной итерации.
В противном случае просто отметьте list.isEmpty()
.
Ответ 6
Вы можете создать класс утилиты со статическими методами, например:
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;
}
}
Ответ 7
Мне легче всего следовать этому соглашению:
-
Если точкой моих методов является возврат коллекции, метод никогда не возвращает значение null. Нуль неоднозначен. Вместо этого я возвращаю Collection.emptyXXX()
или ImmutableXXX.of()
при использовании Guava.
-
Если у меня есть объект, который поддерживает внутренний список в качестве члена, создайте его в конструкторе. Я стараюсь не делать ленивого экземпляра, если не могу доказать его значительную выгоду, потому что ленивый код, на мой взгляд, как правило, сложнее отлаживать, когда возникают проблемы.
Я действительно вижу неизменяемые или немодифицируемые пустые коллекции, являющиеся частью контракта, внешнего по отношению к объектам. Если вы используете внутреннюю коллекцию, я могу реально увидеть использование неизменяемых коллекций, если у вас есть веская причина (concurrency, согласованность, неизменность объекта)