JavaRush /Java блог /Random UA /Double brace ініціалізація
Joysi
41 рівень

Double brace ініціалізація

Стаття з групи Random UA

1. Double brace ініціалізація

Ініціалізація з використанням подвійних фігурних дужок ( далі - Double brace ініціалізація ) - Java засіб для створення колекцій таких як list, set і map одночасно з їх оголошенням.
Double brace ініціалізація - 1
Якщо вам необхідні списки з фіксованими елементами, такі як перелік підтримуваних продуктів або грошових одиниць, оголошення списку одночасно з його ініціалізацією покращує читабельність коду. Саме тому Double brace ініціалізація набирає популярності, оскільки інших стандартних способів створення з одночасною ініціалізацією в коді для колекцій немає. На жаль, на відміну від інших мов програмування, Java не підтримує колекції літералів. Відповідно до даного обмеження, створення незмінного списку ( unmodifiableList ) навіть з невеликою кількістю елементів змушує нас писати багато рядків коду у вигляді повторюваних викликів add()для додавання потрібних елементів із завершальним обгортанням (wrapping):
List<Integer> list = new ArrayList<>();
list.add(2);
list.add(3);
list.add(5);
list.add(7);
List<Integer> unmodifiableList = Collections.unmodifiableList(list);
Це надмірно надлишковий опис, який можна спростити. Заповнимо статичні списки зручним для нас способом, а саме безпосередньо в статичних блоках при ініціалізації, в чому нам і допоможе Double braceініціалізація, що дозволяє нам записати все в один рядок:
List<Integer> list = Collections.unmodifiableList(new ArrayList<Integer>() {{
        add(2);
        add(3);
        add(5);
}});
Аналогічно Double braceініціалізація допоможе нам заповнити значеннями та HashMap:
Map<Integer, String> intToString = new HashMap<Integer, String>(){{
         put(1, "one");
         put(2, "two");
         put(3, "three");
 }};
Все це так елегантно виглядає, проте має свої недоліки, які й роблять Double brace ініціалізацію антишаблоном. Розглянемо їх далі у наступному розділі.

Плюси та мінуси Double brace ініціалізації.

Doublebrace ініціалізація використовує створення внутрішнього анонімного класу ( anonymous inner class ). Що спочатку зовні приховано, проте Double braceініціалізація створює клас з подальшою ініціалізацією його екземпляра, щоразу, як ви застосовуєте її. Крім цього використовується приховане посилання на цей закритий клас, що може призвести до можливих витоків пам'яті. Ви також не зможете використовувати оператор привиду для generic-ів (diamond operator < >), оскільки ми не можемо звернутися всередину анонімного класу.
(Від перекладача: Ще раз детальніше:
після першої {створюється внутрішній анонімний клас, після другої {відбувається ініціалізація при створенні екземпляра класу при якій ми маємо доступ до полів та методів зовнішнього (по відношенню до анонімного) класу.)
Плюси:
  1. Зменшення рядків у коді
  2. Створення та ініціалізація в одному виразі.
Мінуси:
  1. Приховане від вас створення анонімного класу.
  2. Що коштує нам додаткових витрат для його екземпляра щоразу при використанні.
  3. Щоразу створюється приховане посилання на нього, яке, можливо, призведе до витоків пам'яті.
Вердикт: через вищезгадані мінуси та існування альтернатив Double brace ініціалізація розглядається як анти-шаблон у світі Java. Врятуйте кошеня

Альтернативи Double brace ініціалізації у Java

Хороша новина полягає в тому, що є інші способи досягнення тих же цілей в Java. Ми можемо реалізувати в одному рядку коду створення та ініціалізацію значеннями ArrayList використовуючи Copy constructor з Collection класу як показано нижче:
List<Integer> list = Collections.unmodifiableList(new ArrayList<>(Arrays.asList(2, 3, 5)));
Arrays.asList()поверне нам список фіксованої довжини переданий у ArrayListcopy constructor. Пам'ятайте про різницю між списками фіксованої довжини, що повертаються з Arrays.asList()і Collections.unmodifiableList(): ви не можете додавати або видаляти елементи ArrayList-а, однак ви можете змінити елемент за індексом з використанням set(), чого вам не вдасться зробити зі списком, повернутим Collections.unmodifiableList(). Якщо ви хочете отримати невеликий список – це найкращий спосіб, хоча він буде менш прозорим для Setінших колекцій, так доведеться створити Listперед створеннямSet-А. Але це все ж таки краще, ніж Double brace ініціалізація, тому що в даному випадку не створюється зайвий внутрішній анонімний клас при кожному подібному використанні. Якщо ви працюєте під Java 8, у вас є ще один альтернативний спосіб. JDK 8 Stream API допоможе вам створювати невеликі колекції комбінуючи висновок Stream Factoryметоди в колекцію List:
List<String> list = Collections.unmodifiableList(Stream.of("abc", "bcd", "cde").collect(toList()));
Для Setви можете використовувати Collectors.toSet()метод замість Collectors.toList(), як показано нижче:
Set<String> set = Collections.unmodifiableSet(Stream.of("abc", "bcd", "cde").collect(toSet()));
До речі, Stream collectметоди не гарантують, що згенеровані ними колекції захищені від змін. У Java 8 колекції, які вони повернули (такі як - ArrayList, HashSet, and HashMap), цілком собі звичайні ( ми можемо міняти їх), але цей факт можливо буде виправлений у майбутніх релізах JDK. Це все зараз про Double braceініціалізацію в Java. Цей шаблон є прийнятним для тестів і демонстрацій, але не досить хороший для використання в промисловій експлуатації (production). Через властиві йому мінуси, Double brace ініціалізація став анти-шаблоном у наші дні, особливо враховуючи доступні альтернативи. Сам я все ще використовую цю конструкцію для ініціалізації static map-ів та все. Для Listя волію створювати Collectionsкомбінуючи зі створеннямArray.asListу його конструкторі. А якщо використовую Java 8 – конструкцію з використанням Stream API та collect(). Статті по темі: якщо вам сподобався даний навчальний матеріал і ви хочете дізнатися більше про патерни, принципи і кращі прийоми програмування на Java, можливо ви також ознайомитеся з іншими статтями на нашому сайті . Рекомендована література: якщо ви хочете більше дізнатися про шаблони і кращі практики ви повинні прочитати книгу «Ефективне програмування» Джошуа Блоха , жодна книга не може зайняти її місце. А якщо ви вже наторкалися в Java та шукаєте книгу за шаблонами проектування, гуморний стиль викладу якої цікаво та легко читати – зверніть увагу на «Нед First. Шаблони проектування».
Від перекладача: Я навмисне привів посилання на оригінальну книгу Блоха, тому що переклад її на російську невдалий (наприклад, Builder = конструктор).
What is Double Brace Initialization in Java ? Anti Pattern Example (опублікованій у жовтні 2015 року).
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ