Collections.emptyList () порівняно з новим екземпляром


241

На практиці це краще повертати порожній список , як це :

return Collections.emptyList();

Або як це :

return new ArrayList<Foo>();

Або це повністю залежить від того, що ви збираєтеся робити з поверненим списком?

Відповіді:


300

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

У тих рідкісних випадках , коли ви дійсно хочете змінити повертається список, Collections.emptyList()і List.of(), таким чином , НЕ хороший вибір.

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


Крім того, emptyList() може не створюватися новий об'єкт при кожному виклику.

Реалізація цього методу не потребує створення окремого списку об'єктів для кожного виклику. Використання цього методу, швидше за все, матиме порівнянні витрати з використанням поля з назвою, що називається. (На відміну від цього методу, поле не забезпечує безпеку типу.)

Реалізація emptyListвиглядає наступним чином:

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

Отже, якщо ваш метод (який повертає порожній список) називається дуже часто, такий підхід може навіть дати вам трохи кращі показники як процесора, так і пам'яті.


4
Отже, чи Collections.emptyList()більше підходить, скажімо, перевірка помилок тощо?
мереж

1
Клієнти API не отримають NullPointerException, повернувшись Collections.emptyList()замість null.
realPK

@PK_J робить важливий момент. Collections.emptyList()є ітерабельним і повертає довжину, тому його можна використовувати для циклів, не виключаючи викидання.
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) підтверджує, що це не так. @Atul, від чого це JVM?
wjl

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
Як я намагався наголосити на своєму формулюванні ( може бути життєздатним ): все залежить від вашого випадку використання. Я, як правило, або повертаю колекції, що змінюються, або без змін, а не суміш залежно від того, чи вони порожні чи ні. І щоб протистояти "набагато повільнішій претензії": це нинішня реалізація.
Рене

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