Подтвердить что ты не робот

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() действительно очень уродливая... Мне было интересно, если там лучше способ сделать это или даже совсем другой способ справиться с этим.

4b9b3361

Ответ 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, согласованность, неизменность объекта)