Collections.emptyMap () проти нового HashMap ()


143

Які існують ситуації, коли я можу використовуватись Collections.emptyMap()? У Документації сказано, що я можу використовувати цей метод, якщо хочу, щоб моя колекція була непорушною.

Чому я б хотів незмінну порожню колекцію? У чому сенс?


12
+1 до питання, тому що я ніколи не бачив цього статичного методу
Тім Бендер

ви також можете подивитися на лінзи масштабування google Scala лінзи . EmptyMap та imtabletableMap можна використовувати для створення об'єктів, незмінних. emptyMap - початкова точка. Кожного разу, коли елемент додається, сама карта замінюється картою, що містить старий елемент та нові елементи. Справа в тому, що доступ до об’єкта є безпечним.
michael_s

1
Це як у Objective-C [NSArray array], але він повертає об'єкт, який хоч і не корисний, але існує. Тож ви можете грати з ним як із звичайним об’єктом і не отримувати помилки.
Шейн Хсу

Відповіді:


144

З Ефективної Java , елемент № 43 - "Return empty arrays or collections, not null"демонструє повернення порожньої колекції і, можливо, навіть демонструє, використовуючи ці emptyList(), emptySet()та emptyMap()методи класу Collections, щоб отримати порожню колекцію, яка також має додаткову перевагу від непорушності. З пункту №15 "Minimize Mutability" .

З колекцій-порожніх-колекцій-порожніх-списків-колекцій

Це тип ідіоми програмування. Це для людей, які не хочуть нульових змінних. Отже, перш ніж набір ініціалізується, вони можуть використовувати порожній набір.

Примітка. Нижче наведено лише приклад (змінити його відповідно до випадку використання):

private Set myset = Collections.emptySet();

void initSet() {
   myset = new HashSet();
}
void deleteSet() {
   myset = Collections.emptySet();
}

Ці методи пропонують пару переваг:

  1. Вони більш стислі, тому що вам не потрібно чітко вводити загальний тип колекції - це, як правило, виведено з контексту виклику методу.

  2. Вони ефективніші, оскільки не турбуються про створення нових об'єктів; вони просто повторно використовують наявний порожній і незмінний об’єкт. Цей ефект, як правило, дуже незначний, але це час від часу (ну, рідко) важливо.


15
+1 для ефективної довідки Java. Один ніт: Я б рекомендував параметризувати Setі HashSetу ваших прикладах, оскільки вся суть emptySet()методу та друзів (на відміну від констант Collections.EMPTY_SETтощо) полягає в тому, що вони чудово грають із дженериками. Крім того, використання функції (сировинних типів), яка застаріла з часу Java 5, не є гарним навчальним посібником.
Даніель Приден

4
Я залишаюсь непереконаним ... Чи не вся суть використання Collectionзамість того, nullщоб не Exceptionsкидатися на наступні операції? Використання непорушної колекції просто призведе до якихось інших винятків, які я уявляю. І призначення null, безумовно, не менш ефективне, ніж призначення незмінної константи.
fgysin відновила Моніку

14
@fgysin: Якщо у вас є API, де клієнти повинні змінити колекцію, то так, повернути незмінну колекцію немає сенсу. Але якщо у вас є API, де ви повертаєте колекцію, яку клієнти не повинні змінювати, а її слід просто повторити, повернення перегляду до базової колекції має ідеальний сенс для того, щоб переконатися, що "поганий" клієнт не змінив випадково власні колекції Вами. Повернення порожньої колекції замість null означає, що ваш клієнт не повинен робити нульову перевірку перед використанням колекції, роблячи код клієнта більш зрозумілим.
Жан Хомінал

4
public boolean setExists() { return !myset.equals(Collections.emptySet()); }
assylias

5
У вашому прикладі ви чітко перевіряєте порожній набір і використовуєте його як дозорне значення, і ваш клас є змінним. У вашому невеликому прикладі використовуються дозорні та змінювані можливості, саме це і намагається запобігти Collections.emptySet ().
Marc O'Morain

33

На мій особистий досвід, правда, це дуже корисно у випадках, коли API вимагає збору параметрів, але ви нічого не можете надати. Наприклад, у вас може бути API, який виглядає приблизно так і не дозволяє нульових посилань:

public ResultSet executeQuery(String query, Map<String, Object> queryParameters);

Якщо у вас є запит, який не приймає жодних параметрів, створити HashMap, який передбачає виділення масиву, буде дещо марно, коли ви можете просто перейти в "Порожню карту", яка фактично є постійною, як це реалізовано в java.util.Collections.


22

Чому я б хотів незмінну порожню колекцію? У чому сенс?

Тут є два різних поняття, які виглядають дивними при спільному розгляді. Це має більше сенсу, коли ви розглядаєте ці два поняття окремо.

  • По-перше, вам слід віддати перевагу використовувати незмінну колекцію, а не змінну, де це можливо. Переваги імунітету добре зафіксовані в інших місцях .

  • По-друге, вам слід скористатися порожньою колекцією, а не використовувати null як дозорну. Це добре описано тут . Це означає, що у вас буде набагато чистіший, простіший для розуміння код, з меншою кількістю місць для приховування помилок.

Тож, коли у вас є код, який вимагає карту, краще вказати порожню карту, а не нульову, щоб вказати на відсутність карти. І більшу частину часу, коли ви використовуєте карту, краще скористатися незмінною картою. Ось чому для цього є зручна функція зробити незмінну порожню карту.


8

Є кілька випадків, коли ви вважаєте за краще використовувати незмінні карти, списки, набори чи інші типи колекцій.

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

У цьому випадку я вважаю за краще повертати незмінні версії цих версій, оскільки це відображає фактичну незмінність набору результатів обчислення набагато чіткіше - незалежно від того, що ви робите з даними пізніше, набір результатів, отриманих у вашому запиті, не повинен змінити.

Другий випадок загального використання - це коли вам потрібно надати аргумент як вхід до методу чи послуги. Якщо ви не очікуєте, що колекція входів буде модифікована службою чи методом (що зазвичай є дуже поганою ідеєю дизайну), передача в незмінну колекцію замість змінної може бути розумним і безпечним вибором у багатьох випадках.

Я вважаю це конвенцією "передачі цінності" .

Більш загально - розумна практика використовувати незмінні структури даних, коли дані перетинають модуль або межі обслуговування. Це значно спрощує міркування про відмінності між (незмінним) входом / виходом та зміненим внутрішнім станом.

Як дуже корисний побічний ефект цього - підвищена безпека та безпека потоків ваших модулів / служб та забезпечує більш чітке розділення проблем.

Ще однією вагомою причиною використання Collections.empty*()методів є їх помітна відсутність багатослівності. У епоху перед Java7, якщо у вас була загальна колекція, вам довелося розповсюджувати примітки загального типу всюди.

Просто порівняйте ці дві декларації:

Map<Foo, Comparable<? extends Bar>> fooBarMap = new HashMap<Foo, Comparable<? extends Bar>>();

проти:

Map<Foo, Comparable<? extends Bar>> fooBarMap = Collections.emptyMap();

Останній чітко виграє «читання» двома важливими способами:

  1. У першій декларації вся інстанція порожньої карти закопується в шум декларацій загального типу, що робить по суті тривіальне оголошення набагато більш виразним, ніж потрібно.
  2. Окрім помітної відсутності анотації загального типу з правого боку, друга версія чітко говорить про те, що карта ініціалізується на порожню карту. Крім того - знаючи, що цей метод повертає непорушну карту, мені зараз легше знайти, куди fooBarMapпризначається інше непорожнє значення, просто за допомогою пошуку /fooBarMap =/.

5

Для одного ви можете піти з обміну посиланнями. Для new HashMap()тощо потрібен буде виділений об'єкт та, можливо, деякі додаткові елементи для зберігання даних, але вам потрібна лише одна копія незмінного порожнього зібрання (список, набір, карта чи будь-який інший подібний). Це робить очевидним вибір, коли метод, який ви телефонуєте, повинен прийняти карту, але не потрібно її редагувати.

Я пропоную перевірити Ефективну Java Джоша Блоха , в якій перераховані деякі дуже приємні атрибути незмінних об'єктів (включаючи безпеку ниток).


3

Це може бути корисно, коли у вас є функція, яка повертає, immutable collectionі в деяких ситуаціях немає даних для повернення, тому замість повернення nullви можете повернутисяemptyMap()

Це полегшує ваш код і запобігає NullPointerException


3

Більшу частину часу ми використовуємо constructorдля створення нового empty map. Але Collections methodsпропонуємо пару переваг для створення empty mapвикористанняstatic method java.util.Collections.emptyMap()

  1. Вони більш стислі, тому що вам не потрібно чітко вводити загальний тип колекції - він, як правило, виводиться з контексту виклику методу.

  2. Вони ефективніші, оскільки не турбуються про створення нових об'єктів; вони просто повторно використовують наявний порожній і незмінний об’єкт. Цей ефект, як правило, дуже незначний, але це час від часу (ну, рідко) важливо.


2

Чому я б хотів незмінну порожню колекцію? У чому сенс?

З тієї ж причини, яку ви і використали Collections.unmodifiableMap() у якийсь момент. Ви хочете повернути екземпляр Map, який видаляє виняток, якщо користувач намагається його змінити. Це просто особливий випадок: порожня Карта.


1

Чому я б хотів незмінну порожню колекцію? У чому сенс?

З тих самих причин, чому ви можете хотіти незмінних об'єктів. Передусім тому, що ви можете спати вночі в безпеці, знаючи, що декілька потоків можуть отримати доступ до одного і того ж екземпляра об'єкта і що всі вони будуть бачити однакові значення. Якщо у колекції немає елементів, це все-таки дійсне значення, яке ви хочете зберегти.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.