1. Въведение
В този бърз урок ще проучим как можем да инициализираме Списък с помощта на еднолинейни линии.
2. Създаване от масив
Можем да създадем Списък от масив и благодарение на литералите на масива можем да ги инициализираме в един ред:
List list = Arrays.asList(new String[]{"foo", "bar"});
Можем да се доверим на механизма varargs, за да се справи със създаването на масива. По този начин можем да напишем по-кратък и четим код:
@Test public void givenArraysAsList_thenInitialiseList() { List list = Arrays.asList("foo", "bar"); assertTrue(list.contains("foo")); }
Резултатният екземпляр на този код реализира интерфейса List, но не е java.util.ArrayList, нито LinkedList . Вместо това това е Списък, подкрепен от оригиналния масив, който има две последици.
Въпреки това, името на класа е ArrayList, но в пакета java.util.Arrays .
2.1. Фиксиран размер
Екземплярът на резултата от Arrays.asList ще има фиксиран размер:
@Test(expected = UnsupportedOperationException.class) public void givenArraysAsList_whenAdd_thenUnsupportedException() { List list = Arrays.asList("foo", "bar"); list.add("baz"); }
2.2. Споделена справка
Оригиналният масив и списъкът споделят едни и същи препратки към обектите:
@Test public void givenArraysAsList_whenCreated_thenShareReference(){ String[] array = {"foo", "bar"}; List list = Arrays.asList(array); array[0] = "baz"; assertEquals("baz", list.get(0)); }
3. Създаване от поток (Java 8)
Ние можем лесно да конвертираме поток във всякакъв вид колекция.
Следователно с фабричните методи за потоци можем да създаваме и инициализираме списъци в един ред:
@Test public void givenStream_thenInitializeList(){ List list = Stream.of("foo", "bar") .collect(Collectors.toList()); assertTrue(list.contains("foo")); }
Тук трябва да отбележим, че Collectors.toList () не гарантира точното изпълнение на върнатия Списък .
Няма общ договор относно променливостта, сериализацията или безопасността на нишките на върнатия екземпляр. Следователно нашият код не трябва да разчита на нито едно от тези свойства.
Някои източници подчертават, че Stream.of (...) .collect (...) може да има по-голям обем памет и производителност от Arrays.asList (), но в почти всички случаи това е такава микро-оптимизация, че има малка разлика.
4. Фабрични методи (Java 9)
В JDK 9 са въведени няколко удобни фабрични метода за колекции:
List list = List.of("foo", "bar", "baz"); Set set = Set.of("foo", "bar", "baz");
Важна подробност е, че върнатите екземпляри са неизменни . Освен това фабричните методи имат няколко предимства в космическата ефективност и безопасността на конеца.
Тази тема е разгледана повече в тази статия.
5. Инициализация с двойна скоба
На няколко места можем да намерим метод, наречен „инициализация с двойна скоба“, който изглежда така:
@Test public void givenAnonymousInnerClass_thenInitialiseList() { List cities = new ArrayList() {{ add("New York"); add("Rio"); add("Tokyo"); }}; assertTrue(cities.contains("New York")); }
Името „двойна скоба инициализация“ е доста подвеждащо. Синтаксисът може да изглежда компактен и елегантен, но опасно скрива това, което се случва под капака.
Всъщност в Java няма синтаксисен елемент „двойна скоба“ , това са два блока, форматирани умишлено по този начин.
С външните скоби декларираме анонимен вътрешен клас, който ще бъде подклас на ArrayList . Вътре в тези скоби можем да декларираме подробностите за нашия подклас.
Както обикновено, можем да използваме блокове за инициализация на екземпляри и оттам идват вътрешните двойки скоби.
Краткостта на този синтаксис е примамлива, но се счита за анти-модел.
За да прочетете повече за инициализацията с двойни скоби, погледнете нашата статия тук.
6. Заключение
Съвременната Java предлага няколко опции за създаване на колекция в един ред. Избраният от нас метод е почти изцяло до личните предпочитания, а не от техническите разсъждения.
Важен извод е, че макар и да изглежда грациозно, анти-моделът на анонимната инициализация на вътрешен клас (известен още като „двойна скоба“) има много негативни странични ефекти .
Както винаги, кодът е достъпен в GitHub.