Collections.emptyList () против нового экземпляра


241

На практике лучше вернуть пустой список примерно так :

return Collections.emptyList();

Или вот так :

return new ArrayList<Foo>();

Или это полностью зависит от того, что вы собираетесь делать с возвращенным списком?

Ответы:


300

Основное отличие состоит в том, что Collections.emptyList()возвращает неизменный список, т. Е. Список, в который нельзя добавлять элементы. (То же относится и к List.of()введенному в Java 9.)

В тех редких случаях , когда вы действительно хотите изменить возвращаемый список, Collections.emptyList()и List.of(), таким образом , не хороший выбор.

Я бы сказал, что возвращение неизменяемого списка совершенно нормально (и даже предпочтительным образом), если в контракте (документации) явно не указано иное.


Кроме того, emptyList() может не создавать новый объект с каждым вызовом.

Реализации этого метода не должны создавать отдельный объект List для каждого вызова. Использование этого метода может иметь сравнимую стоимость с использованием одноименного поля. (В отличие от этого метода, поле не обеспечивает безопасность типов.)

Реализация emptyListвыглядит следующим образом:

public static final <T> List<T> emptyList() {
    return (List<T>) EMPTY_LIST;
}

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


4
Итак, Collections.emptyList()подойдет ли, скажем так, проверка ошибок и тому подобное?
MRE

1
Клиенты API не получат NullPointerException, вернув Collections.emptyList()вместо null.
realPK

@PK_J делает важный момент. Collections.emptyList()является итеративным и возвращает длину, поэтому его можно использовать в циклах for без исключения.
ndm13

как насчет использования List.of()?

4
@ AJW, да. Но по сравнению, скажем, new ArrayList<>()это также делает проектное решение ясным; элементы не будут добавлены в этот список.
aioobe

51

Начиная с Java 5.0, вы можете указать тип элемента в контейнере:

Collections.<Foo>emptyList()

Я согласен с другими ответами, что для случаев, когда вы хотите вернуть пустой список, который остается пустым, вы должны использовать этот подход.


38
Начиная с Java 7, вы можете позволить компилятору выводить параметр типа вызова универсального метода из целевого типа:List<Foo> list = Collections.emptyList()
Пол Джексон

28

Collections.emptyList является неизменным, поэтому существует разница между двумя версиями, поэтому вы должны учитывать пользователей возвращаемого значения.

Возврат new ArrayList<Foo>всегда создает новый экземпляр объекта, поэтому с ним связаны очень небольшие дополнительные расходы, которые могут дать вам повод для использования Collections.emptyList. Мне нравится использовать emptyListтолько потому, что это более читабельно.


14

Будьте осторожны, хотя. Если вы вернетесь, Collections.emptyList()а затем попытаетесь внести в него некоторые изменения, например add()или что-то в этом роде, у вас будет UnsupportedOperationException()потому что Collections.emptyList()возвращает неизменный объект.


7

Я хотел бы пойти с, Collections.emptyList()если возвращенный список не изменяется каким-либо образом (так как список является неизменным), в противном случае я бы пошел с вариантом 2.

Преимущество Collections.emptyList()заключается в том, что каждый раз возвращается один и тот же статический экземпляр, поэтому создание экземпляра для каждого вызова не происходит.


3

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

/**
 * The empty list (immutable). 
 */
public static final List EMPTY_LIST = new EmptyList();

Я прибыл сюда, пытаясь выяснить, была ли стоимость звонка Collections.emptyList()строительства. Просмотр подробностей реализации (хотя, вероятно, не одинаковых на всех JVM) подтверждает, что это не так. @ Атул, из какой это JVM?
13

2

Приведенные ответы подчеркивают тот факт, что emptyList()возвращает неизменное, Listно не дают альтернативы. Конструктору ArrayList(int initialCapacity)особые случаи 0так возвращающиеся new ArrayList<>(0)вместо new ArrayList<>()также может быть жизнеспособным решением:

/**
 * Shared empty array instance used for empty instances.
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

[...]

/**
 * Constructs an empty list with the specified initial capacity.
 *
 * @param  initialCapacity  the initial capacity of the list
 * @throws IllegalArgumentException if the specified initial capacity
 *         is negative
 */
public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}

(исходники из Java 1.8.0_72)


Я не согласен с вашим подходом. Вы экономите немного памяти и ЦП при инициализации, но если список, который вы вернули, когда-либо изменяется, вы теряете то время, когда список перераспределяет новый массив. Если со временем в список будет добавлено много элементов, это может привести к увеличению узкого места в производительности из- за гораздо более медленного роста . Я предпочитаю придерживаться соглашения о неизменяемом пустом списке или пригодном для использования, изменяемом списке.
Патрик М

1
Как я пытался подчеркнуть с моей формулировкой ( может быть жизнеспособным ): все зависит от вашего варианта использования. Я , как правило , либо возвращать изменяемую или unmutable Коллекции, не смесь в зависимости от кастрированного барана они пустые или нет. И противостоять «гораздо более медленным претензиям»: это текущая реализация.
Рене

О, чувак, посмотри на меня, ссылаясь на то, что JDK 2 основных версии устарели. Таким образом, java8 полностью устраняет узкое место, перепрыгивая на емкость по умолчанию с начального размера 0. Извините, я был так неправ.
Патрик М
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.