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

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

1. Вступление

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

Дальнейшее чтение:

Collections.emptyList() vs. Новый экземпляр списка

Узнайте различия между Collections.emptyList () и новым экземпляром списка.

Read more

Руководство по Java ArrayList

Краткое и практическое руководство по ArrayList в Java

Read more

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

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

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

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

@Test
public void givenArraysAsList_thenInitialiseList() {
    List list = Arrays.asList("foo", "bar");

    assertTrue(list.contains("foo"));
}

The result instance of this code implements the List interface but it isn’t a java.util.ArrayList nor a LinkedList. Вместо этого этоList, поддерживаемый исходным массивом, что имеет два значения.

Хотя имя класса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)

Мы можем легко преобразоватьStream в любой видCollection.

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

@Test
public void givenStream_thenInitializeList(){
    List list = Stream.of("foo", "bar")
      .collect(Collectors.toList());

    assertTrue(list.contains("foo"));
}

Здесь следует отметить, чтоCollectors.toList() не гарантирует точную реализацию возвращенногоList.

There’s no general contract about the mutability, serializability or thread-safety of the returned instance. Следовательно, наш код не должен полагаться ни на одно из этих свойств.

Некоторые источники подчеркивают, чтоStream.of(…).collect(…) может иметь больший объем памяти и производительности, чемArrays.asList(), но почти во всех случаях это такая микрооптимизация, что разница невелика.

4. Фабричные методы (Java 9)

В JDK 9 было представлено несколько удобных фабричных методов для коллекций:

List list = List.of("foo", "bar", "baz");
Set set = Set.of("foo", "bar", "baz");

One important detail is the returned instances are immutable. Помимо этого, у заводских методов есть несколько преимуществ в эффективности использования пространства и безопасности резьбы.

Эта тема более подробно рассматривается вthis article.

5. Двойная инициализация

В нескольких местах мы можем найти метод под названием‘double brace initialization', который выглядит так:

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

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

Название‘double brace initialization' вводит в заблуждение. Синтаксис может выглядеть компактно и элегантно, но он опасно скрывает то, что происходит под капотом.

Фактически в Java нет элемента синтаксиса‘double brace', это два блока, отформатированных таким образом намеренно.

With the outer braces, we declare an anonymous inner class which will be a subclass of the ArrayList. Внутри фигурных скобок мы можем объявить детали нашего подкласса.

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

Краткость этого синтаксиса заманчива, но считается антипаттерном.

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

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

Modern Java offers several options to create a Collection in one line. Выбранный нами метод почти полностью зависит от личных предпочтений, а не от технических соображений.

Важный вывод: хотя это выглядит изящно,the anti-pattern of anonymous inner class initialization (a.k.a. ‘double brace') has many negative side-effects.

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