Перейти к основному содержимому

Инициализация списка Java в одну строку

· 3 мин. чтения

1. Обзор

В этом кратком руководстве мы рассмотрим, как инициализировать список с помощью однострочников.

2. Создать из массива

Мы можем создать список из массива. А благодаря литералам массивов мы можем инициализировать их одной строкой:

List<String> list = Arrays.asList(new String[]{"foo", "bar"});

Мы можем доверять механизму varargs для обработки создания массива. Благодаря этому мы можем написать более лаконичный и читаемый код:

@Test
public void givenArraysAsList_thenInitialiseList() {
List<String> 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<String> list = Arrays.asList("foo", "bar");

list.add("baz");
}

2.2. Общая ссылка

Исходный массив и список имеют одни и те же ссылки на объекты:

@Test
public void givenArraysAsList_whenCreated_thenShareReference(){
String[] array = {"foo", "bar"};
List<String> list = Arrays.asList(array);
array[0] = "baz";

assertEquals("baz", list.get(0));
}

3. Создать из потока (Java 8)

Мы можем легко преобразовать поток в любую коллекцию.

Поэтому с фабричными методами для Streams мы можем создавать и инициализировать списки в одну строку:

@Test
public void givenStream_thenInitializeList(){
List<String> 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<String> list = List.of("foo", "bar", "baz");
Set<String> set = Set.of("foo", "bar", "baz");

Одна важная деталь заключается в том, что возвращаемые экземпляры неизменяемы. Кроме того, фабричные методы имеют несколько преимуществ в эффективности использования пространства и безопасности потоков.

Эта тема более подробно рассматривается в этой статье .

5. Инициализация с помощью двойной скобки

В нескольких местах мы можем найти метод, называемый инициализацией двойной скобки, который выглядит так:

@Test
public void givenAnonymousInnerClass_thenInitialiseList() {
List<String> cities = new ArrayList() {{
add("New York");
add("Rio");
add("Tokyo");
}};

assertTrue(cities.contains("New York"));
}

Название «инициализация с двойными скобками» вводит в заблуждение. Хотя синтаксис может выглядеть компактным и элегантным, он опасно скрывает то, что происходит под капотом.

На самом деле в Java нет синтаксического элемента с двойной скобкой; это два блока, намеренно отформатированные таким образом.

С помощью внешних фигурных скобок мы объявляем анонимный внутренний класс, который будет подклассом ArrayList . Мы можем объявить детали нашего подкласса внутри этих фигурных скобок.

Как обычно, мы можем использовать блоки инициализации экземпляра, и именно отсюда берется внутренняя пара фигурных скобок.

Краткость этого синтаксиса заманчива. Тем не менее, это считается анти-шаблоном.

Чтобы узнать больше об инициализации с помощью двойных скобок, ознакомьтесь с нашей статьей здесь .

6. Заключение

Современная Java предлагает несколько вариантов создания коллекции в одну строку. Метод, который мы выбираем, почти полностью зависит от личных предпочтений, а не от технических соображений.

Важным выводом является то, что антишаблон анонимной инициализации внутреннего класса (также известный как двойная фигурная скобка) хотя и выглядит изящно, но имеет много негативных побочных эффектов.

Как всегда, код доступен на GitHub .