Java 9 представила нові фабричні методи для списків List.of
:
List<String> strings = List.of("first", "second");
Яка різниця між попереднім та новим варіантом? Тобто, в чому різниця між цим:
Arrays.asList(1, 2, 3);
і це:
List.of(1, 2, 3);
Java 9 представила нові фабричні методи для списків List.of
:
List<String> strings = List.of("first", "second");
Яка різниця між попереднім та новим варіантом? Тобто, в чому різниця між цим:
Arrays.asList(1, 2, 3);
і це:
List.of(1, 2, 3);
Відповіді:
Arrays.asList
повертає змінюваний список , а список повертається List.of
є непорушним :
List<Integer> list = Arrays.asList(1, 2, null);
list.set(1, 10); // OK
List<Integer> list = List.of(1, 2, 3);
list.set(1, 10); // Fails with UnsupportedOperationException
Arrays.asList
дозволяє нульові елементи, а List.of
не:
List<Integer> list = Arrays.asList(1, 2, null); // OK
List<Integer> list = List.of(1, 2, null); // Fails with NullPointerException
contains
поводиться по-різному з нулями:
List<Integer> list = Arrays.asList(1, 2, 3);
list.contains(null); // Returns false
List<Integer> list = List.of(1, 2, 3);
list.contains(null); // Fails with NullPointerException
Arrays.asList
повертає перегляд пройденого масиву, тому зміни масиву будуть відображені і в списку. Бо List.of
це не вірно:
Integer[] array = {1,2,3};
List<Integer> list = Arrays.asList(array);
array[1] = 10;
System.out.println(list); // Prints [1, 10, 3]
Integer[] array = {1,2,3};
List<Integer> list = List.of(array);
array[1] = 10;
System.out.println(list); // Prints [1, 2, 3]
List.contains(Object o)
's javadoc : "Кидає [...] NullPointerException - якщо вказаний елемент є нульовим і цей список не дозволяє нульових елементів (необов'язково)". Або з тривалого вступу інтерфейсу, який мало хто читає: "Деякі реалізації колекції мають обмеження на елементи, які вони можуть містити"
List.of
дійсно повертають деякий ImmutableList
тип, його фактичну назву просто деталь непублічної реалізацій. Якщо вона була загальнодоступною і хтось кинув її List
знову, де була різниця? Де різниця Arrays.asList
, яка повертає непублічну List
реалізацію, яка викидає виняток при спробі add
або remove
, або список, повернений, Collections.unmodifiableList
який не дозволяє змінювати взагалі? Вся справа в контрактах, зазначених в List
інтерфейсі. Інтерфейси колекцій з додатковими методами завжди були нечистими OOP з Java 1.2…
Arrays.asList
іList.of
Дивіться JavaDocs і цю розмову Stuart Marks (або попередні версії).
Я буду використовувати наступні приклади коду:
List<Integer> listOf = List.of(...);
List<Integer> asList = Arrays.asList(...);
List<Integer> unmodif = Collections.unmodifiableList(asList);
Будь-яка спроба структурно зміни List.of
призведуть до UnsupportedOperationException
. Це включає такі операції, як додавання , встановлення та видалення . Однак ви можете змінити вміст об'єктів у списку (якщо об'єкти не є незмінними), тому список не є "повністю незмінним".
Така сама доля для немодифікуючих списків, створених за допомогою Collections.unmodifiableList
. Лише цей список - це перегляд оригінального списку, тому він може змінитися, якщо змінити оригінальний список.
Arrays.asList
не є повністю незмінним, не має обмеження на set
.
listOf.set(1, "a"); // UnsupportedOperationException
unmodif.set(1, "a"); // UnsupportedOperationException
asList.set(1, "a"); // modified unmodif! unmodif is not truly unmodifiable
Аналогічно, зміна резервного масиву (якщо ви його утримуєте) змінить список.
Структурна незмінність має багато побічних ефектів, пов'язаних з оборонним кодуванням, одночасністю та безпекою, які виходять за рамки цієї відповіді.
List.of
і будь-яка колекція, оскільки Java 1.5 не дозволяє null
в якості елемента. Спроба перейти null
як елемент або навіть пошук призведе до а NullPointerException
.
Оскільки Arrays.asList
це колекція з 1.2 (Framework Collection), вона дозволяє null
s.
listOf.contains(null); // NullPointerException
unmodif.contains(null); // allowed
asList.contains(null); // allowed
Оскільки List.of
впроваджено в Java 9, а списки, створені цим методом, мають свою (бінарну) серіалізовану форму, їх не можна десеріалізувати у попередніх версіях JDK (відсутність бінарної сумісності ). Однак, ви можете де / серіалізувати, наприклад, JSON.
Arrays.asList
внутрішні дзвінки new ArrayList
, що гарантує опорну нерівність.
List.of
залежить від внутрішньої реалізації. Повернені екземпляри можуть мати еталонну рівність, але оскільки це не гарантується, ви не можете покластися на нього.
asList1 == asList2; // false
listOf1 == listOf2; // true or false
Варто зазначити, що списки рівні (через List.equals
), якщо вони містять однакові елементи в одному порядку, незалежно від того, як вони були створені або які операції вони підтримують.
asList.equals(listOf); // true i.f.f. same elements in same order
Якщо кількість елементів у списку List.of
становить 2 або менше, елементи зберігаються у полях спеціалізованого (внутрішнього) класу. Прикладом є список, який зберігає 2 елементи (часткове джерело):
static final class List2<E> extends AbstractImmutableList<E> {
private final E e0;
private final E e1;
List2(E e0, E e1) {
this.e0 = Objects.requireNonNull(e0);
this.e1 = Objects.requireNonNull(e1);
}
}
В іншому випадку вони зберігаються в масиві аналогічно до Arrays.asList
.
На List.of
деяких полях реалізація (розмір <2) виконує трохи швидше. Як приклад, size()
можна повернути константу, не вибираючи довжину масиву, і contains(E e)
не вимагає ітерації накладних витрат.
Створення немодифікованого списку List.of
також є більш швидким. Порівняйте вищезазначений конструктор з двома еталонними призначеннями (і навіть тим, для довільної кількості елементів)
Collections.unmodifiableList(Arrays.asList(...));
який створює 2 списки плюс інші накладні витрати. З точки зору простору, ви заощаджуєте UnmodifiableList
обгортку плюс деякі копійки. Зрештою, економія в HashSet
еквіваленті є більш переконливою.
Час висновку: використовуйте, List.of
коли потрібно список, який не змінюється, і Arrays.asList
коли ви хочете змінити список (як показано вище).
Arrays.asList
не повністю змінюється. asList.add(1);
кидає UnsupportedOperationException
.
List.of
жоден час, коли люди можуть захотіти зателефонувати contains
і не здивуватися NullPointerException.
Нехай узагальнить відмінності між List.of та Arrays.asList
List.of
можна найкраще використовувати, коли набір даних менший і незмінний, тоді Arrays.asList
як найкраще використовувати у випадку великого та динамічного набору даних.
List.of
займають дуже менше надземного простору, оскільки він має польову реалізацію і споживає менше місця нагромадження, як з точки зору фіксованих накладних витрат, так і на основі елемента. при цьому Arrays.asList
займайте більше накладного простору, оскільки при ініціалізації це створює більше об'єктів у купі.
Колекція, що повертається, List.of
є непорушною, а значить, безпечною для потоків, тоді як колекція, що повертається, Arrays.asList
є змінною, а не захищеною від потоку. (Незмінні екземпляри колекції, як правило, споживають набагато менше пам'яті, ніж їх аналоги, що змінюються.)
List.of
не дозволяє нульові елементи, в той час як Arrays.asList
дозволяє нульові елементи.
Arrays.asList
проти List.of
, враховуючи, що колишня буквально просто обгортка навколо масиву. Принаймні , впровадження OpenJDK має надзвичайно невеликі витрати. Насправді, List.of
потрібно було б зробити копії будь-якого переданого масиву, тому, якщо сам масив незабаром не стане GC'd, здавалося б, List.of
має значно більший слід пам’яті.
List.of(x)
і List.of(x, y)
ефективніші @ChrisHayes, тому що вони взагалі не виділяють масиви
List.of
методи не потрібно щоразу повертати нові списки. У цих списках не визначена ідентичність, тому на рівні JVM може бути кешоване чи дедупликаційне чи скаларизоване. Якщо ні в цій версії, то, можливо, в наступній. Це дозволено договором. Навпаки, це Array.asList
залежить від ідентичності масиву, який ви передаєте, оскільки отриманий список є змінним видом на масив, відображаючи всі зміни в двосторонній формі.
Крім вищезазначених відповідей, існують певні операції, за якими List::of
і Arrays::asList
відрізняються:
+----------------------+---------------+----------+----------------+---------------------+
| Operations | SINGLETONLIST | LIST::OF | ARRAYS::ASLIST | JAVA.UTIL.ARRAYLIST |
+----------------------+---------------+----------+----------------+---------------------+
| add | ❌ | ❌ | ❌ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| addAll | ❌ | ❌ | ❌ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| clear | ❌ | ❌ | ❌ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| remove | ❌ | ❌ | ❌ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| removeAll | ❗️ | ❌ | ❗️ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| retainAll | ❗️ | ❌ | ❗️ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| replaceAll | ❌ | ❌ | ✔️ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| set | ❌ | ❌ | ✔️ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| sort | ✔️ | ❌ | ✔️ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| remove on iterator | ❌ | ❌ | ❌ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
| set on list-iterator | ❌ | ❌ | ✔️ | ✔️ |
+----------------------+---------------+----------+----------------+---------------------+
Більше про колекції :: singletonList Vs. Список