Collections.emptyList () вместо проверки нуля? - PullRequest
15 голосов
/ 01 июля 2011

Если в каком-то классе у меня есть редко используемая коллекция, которую можно создавать многократно, иногда я могу прибегнуть к следующей «идиоме», чтобы сохранить ненужные создания объектов:

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 в add() следующим образом:

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

Есть ли лучший способ справиться с этим другимчем просто выделять новую пустую коллекцию каждый раз?

РЕДАКТИРОВАТЬ: просто, чтобы было ясно, я хотел бы использовать Collections.emptyList (), но проверка вышеВ add () это действительно ужасно ... Мне было интересно, есть ли лучший способ сделать это или вообще другой способ справиться с этим.

Ответы [ 8 ]

17 голосов
/ 01 июля 2011

для сохранения ненужных созданий объектов

Это действительно плохая идея, которая засоряет ваш код проверками == null и другой обработкой угловых случаев (и в любом случае, по-видимому, в конечном итоге приводит к исключениям нулевого указателя)!

Теперь мне было интересно, не смогу ли я отменить эти нулевые проверки, используя Collections.emptyList()

Нет, не совсем. emptyList() возвращает пустой список. Вы могли бы сделать

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

но это все равно вызовет исключение NullPointerException, если list == null, так что это все еще не то, что вы ищете.

Моя рекомендация: всегда инициализируйте список как new ArrayList<Object>, или, если вы, например, хотите вернуть пустой список из метода, используйте вместо него Collections.emptyList(). (При этом каждый раз возвращается один и тот же экземпляр, поэтому создание ненужных объектов там тоже не требуется.)

А затем используйте .isEmpty(), чтобы проверить, является ли коллекция пустой или нет.

10 голосов
/ 30 августа 2016

Предлагаемые ответы абсолютно правильны, просто небольшой совет - в 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;
}
2 голосов
/ 30 октября 2012

Вот то, что я использую для вспомогательного метода в некоторых моих кодах.Действительно хорошо работает, уменьшая тонну нулевых проверок, которые я обычно должен размещать перед итерацией по спискам.Если вам нужен список, который не был бы неизменным, вы можете вернуть новый объект списка вместо 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 только для примера, но вы, очевидно, изменили бы его навсе, что имеет смысл для вашего использования.

2 голосов
/ 01 июля 2011

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++) {
     ;
}
0 голосов
/ 26 февраля 2019

Вот вариант использования необязательного, как предложено @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 использовать пустой массив, если коллекция пуста.

Например:

// no need to indent everything inside a null check of myObjects
for (MyObj myObj : Optional.ofNullable(myObjects).orElse(Collections.emptyList())){
    // do stuff with myObj
}
0 голосов
/ 14 сентября 2012

Мне проще всего следовать этому соглашению:

  1. Если смысл моих методов - вернуть коллекцию, метод никогда не возвращает ноль.Нуль неоднозначен.Вместо этого я возвращаю Collection.emptyXXX() или ImmutableXXX.of() при использовании Guava.

  2. Если у меня есть объект, который поддерживает внутренний список в качестве члена, создайте его экземпляр в конструкторе.Я стараюсь не выполнять ленивую реализацию, если не смогу доказать ее значительную выгоду, потому что ленивый код, , по моему мнению , имеет тенденцию к более трудной отладке при возникновении проблем.1016 * Я действительно вижу неизменяемые или неизменяемые пустые коллекции, являющиеся частью контракта, внешнего по отношению к объектам.Если вы используете коллекцию для внутреннего использования, я действительно могу увидеть использование неизменяемых коллекций только при наличии уважительной причины (параллелизм, согласованность, неизменность объекта)

0 голосов
/ 01 июля 2011

Вы можете создать служебный класс со статическими методами, например:

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;
}

}

0 голосов
/ 01 июля 2011

Если вы используете список только для итераций, вы можете просто использовать: for (Object object : list), который ничего не сделает для пустых списков, то есть ни одной итерации.

В противном случае просто проверьте list.isEmpty().

...