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), вона дозволяє nulls.
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. Список