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


2758

Я хотел создать список опций для целей тестирования. Сначала я сделал это:

ArrayList<String> places = new ArrayList<String>();
places.add("Buenos Aires");
places.add("Córdoba");
places.add("La Plata");

Затем я изменил код следующим образом:

ArrayList<String> places = new ArrayList<String>(
    Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));

Есть лучший способ сделать это?


34
Если это предназначено для модульного тестирования, попробуйте Groovy для качелей. Вы можете написать свой тестовый код в нем во время тестирования Java-кода и использоватьArrasyList<String> places = ["Buenos Aires", "Córdoba", "La Plata"]
ripper234

3
В Java SE 7 вы можете заменить параметризованный тип конструктора пустым набором параметров типа (<>): Map <String, List <String >> myMap = new HashMap <> ();
Роза


2
использовать двойную инициализацию бодрствования :)
Мохаммадреза Хатами

8
Stream.of ("val1", "val2"). Collect (Collectors.toList ()); // создает ArrayList, решение Java8.
Торина

Ответы:


2025

На самом деле, вероятно, «лучший» способ инициализации ArrayList- это метод, который вы написали, так как он не должен создавать новый Listспособ:

ArrayList<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
list.add("C");

Подвох в том, что для ссылки на этот listэкземпляр требуется довольно много печатания .

Есть альтернативы, такие как создание анонимного внутреннего класса с инициализатором экземпляра (также известный как «инициализация двойной скобки»):

ArrayList<String> list = new ArrayList<String>() {{
    add("A");
    add("B");
    add("C");
}};

Тем не менее, я не слишком люблю этот метод, потому что в конечном итоге у вас есть подкласс, в ArrayListкотором есть инициализатор экземпляра, и этот класс создается только для создания одного объекта, что кажется мне немного излишним.

Было бы неплохо, если бы предложение Collection Literals для Project Coin было принято (оно должно было быть представлено в Java 7, но вряд ли оно будет частью Java 8).

List<String> list = ["A", "B", "C"];

К сожалению, это не поможет вам, так как будет инициализировать неизменяемый, Listа не ArrayList, и, более того, он еще не доступен, если он когда-либо будет.


172
См. Stackoverflow.com/questions/924285 для получения дополнительной информации об инициализации двойной скобки, плюсы и минусы.
Эдди

6
@ Эдди: Хороший вызов для ссылки - одного предложения по инициализации в двойных скобках недостаточно для полного описания.
coobird

2
Работает только в том случае, если вы не полагаетесь на Auto Boxing List <Double> list = [1.0, 2.0, 3.0]; выходит из строя.
Ричард Б.

1
Вам не хватает точки с запятой при инициализации двойного списка
Дон Ларинкс

6
Поскольку этот ответ пользуется наибольшим спросом и упоминается в Project Coin, я думаю, вам следует обратиться к java 9 с синтаксисом List.of (...): docs.oracle.com/javase/9/docs/api/java/util/. List.html # of-E ...-
Асаф

2156

Было бы проще, если бы вы просто объявили его как List- это должен быть ArrayList?

List<String> places = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");

Или, если у вас есть только один элемент:

List<String> places = Collections.singletonList("Buenos Aires");

Это будет означать, что оно placesявляется неизменным (попытка изменить его вызовет UnsupportedOperationExceptionисключение).

Чтобы создать конкретный изменяемый список, ArrayListвы можете создать его ArrayListиз неизменяемого списка:

ArrayList<String> places = new ArrayList<>(Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));

18
@Marcase: вы не можете изменить свой класс для использования List вместо ArrayList?
Лоуренс Дол

74
Согласно моему ответу, если вы не используете методы, специфичные для ArrayList, было бы лучше изменить объявление на List. Укажите интерфейсы, а не реализации.
Кристоффер Хаммарстрем

9
@Christoffer Hammarström: если он меняет объявление на List и использует List <String> place = Arrays.asList (...); он не сможет использовать place.add («блабла»)
макс

57
Просто чтобы быть понятным, asList(...)возвращает фиксированный размер, Listкоторый взрывается при мутирующих операциях, таких как removeи clearвещи, которые, как Listутверждает договор, поддерживает. Даже если вы оставили объявление как List, вам все равно придется использовать его List l = new ArrayList(asList(...))для получения объекта, который не генерирует исключения OperationNotSupported. Лисков Принцип подстановки у кого-нибудь?
Всплеск

5
@Splash: removeи clearявляются необязательными операциями в List, так asList(...)же как и в случае с контрактом Нигде ОП не говорит, что ему нужно добавить больше элементов позже, пример только того, Listкоторый нужно инициализировать тремя элементами.
Кристофер Хаммарстрем

872

Простой ответ

В Java 9 или более поздней версии List.of()было добавлено:

List<String> strings = List.of("foo", "bar", "baz");

В Java 10 или более поздней версии это можно сократить с помощью varключевого слова.

var strings = List.of("foo", "bar", "baz");

Это даст вам неизменность List , поэтому его нельзя изменить.
Это то, что вы хотите в большинстве случаев, когда вы его предварительно заполняете.


Java 8 или более ранняя версия:

List<String> strings = Arrays.asList("foo", "bar", "baz");

Это обеспечит вам Listмассив, поэтому он не может изменить длину.
Но вы можете позвонить List.set, так что он все еще изменчив .


Вы можете сделать Arrays.asListеще короче с помощью статического импорта:

List<String> strings = asList("foo", "bar", "baz");

Статический импорт:

import static java.util.Arrays.asList;  

Что любая современная IDE предложит и автоматически сделает для вас.
Например, в IntelliJ IDEA вы нажимаете Alt+Enterи выбираете Static import method....


Однако я не рекомендую сокращать List.ofметод до of, потому что это сбивает с толку.
List.ofуже достаточно короткий и хорошо читает.


Используя Streams

Почему это должно быть List?
С Java 8 или более поздней версии вы можете использовать Streamболее гибкий:

Stream<String> strings = Stream.of("foo", "bar", "baz");

Вы можете объединить Streams:

Stream<String> strings = Stream.concat(Stream.of("foo", "bar"),
                                       Stream.of("baz", "qux"));

Или вы можете пойти от Streamк List:

import static java.util.stream.Collectors.toList;

List<String> strings = Stream.of("foo", "bar", "baz").collect(toList());

Но желательно, просто используйте, Streamне собирая его List.


Если вам действительно нужноjava.util.ArrayList

(Вы, вероятно, нет.)
Цитировать JEP 269 (выделение мое):

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


Если вы хотите как предварительно заполнить ап ArrayList и добавить к нему впоследствии (почему?), Использование

ArrayList<String> strings = new ArrayList<>(List.of("foo", "bar"));
strings.add("baz");

или в Java 8 или ранее:

ArrayList<String> strings = new ArrayList<>(asList("foo", "bar"));
strings.add("baz");

или используя Stream:

import static java.util.stream.Collectors.toCollection;

ArrayList<String> strings = Stream.of("foo", "bar")
                             .collect(toCollection(ArrayList::new));
strings.add("baz");

Но опять же, лучше просто использовать Streamнапрямую, а не собирать его в List.


Программа для интерфейсов, а не для реализаций

Вы сказали, что объявили список ArrayListв своем коде, но вы должны делать это только в том случае, если вы используете какой-то член ArrayList, которого нет в List.

Что вы, скорее всего, не делаете.

Как правило , вы должны просто объявить переменные наиболее общий интерфейс , который вы собираетесь использовать (например Iterable, Collectionили List) и инициализировать их с выполнением конкретной (например ArrayList, LinkedListили Arrays.asList()).

В противном случае вы ограничиваете свой код этим конкретным типом, и изменить его будет сложнее, когда вы захотите.

Например, если вы пропускание ArrayListк void method(...):

// Iterable if you just need iteration, for (String s : strings):
void method(Iterable<String> strings) { 
    for (String s : strings) { ... } 
}

// Collection if you also need .size(), .isEmpty(), or .stream():
void method(Collection<String> strings) {
    if (!strings.isEmpty()) { strings.stream()... }
}

// List if you also need .get(index):
void method(List<String> strings) {
    strings.get(...)
}

// Don't declare a specific list implementation
// unless you're sure you need it:
void method(ArrayList<String> strings) {
    ??? // You don't want to limit yourself to just ArrayList
}

Другим примером будет всегда объявлять переменную a, InputStreamдаже если это обычно a FileInputStreamили a BufferedInputStream, потому что скоро вы или кто-то другой захотите использовать какой-то другой тип InputStream.


3
@jollyroger: Arrays.asListэто статический метод. См. Docs.oracle.com/javase/1.5.0/docs/guide/language/…
Кристоффер Хаммарстрем

2
@ ChristofferHammarström В этом случае мой ум новичка говорит мне, что статический импорт имеет сильное сходство с глобальными переменными и опасностями, которые имеют отношение к такому использованию. Правильно ли это предположение и является ли это причиной того, что аналогичный ответ выше получил больше голосов?
Jollyroger

2
Ответ, о котором вы говорите, был сделан годом ранее. И нет, проблема с глобальными переменными в том, что они изменчивы. Они не имеют ничего общего со статическим импортом.
Христоффер Хаммарстрем

2
Если вам не нужен статический импорт, вы также можете определить полный путь к статическому методу asList, например: List <String> strings = java.util.Arrays.asList ("", "");
Гирт Вининг,

2
Или вы можете использовать import java.util.Arrays; и Arrays.asList ("", ""); Вам не нужно использовать статический импорт. Вам не нужно использовать полный путь. Статические методы не заботятся об импорте. Они просто раздражаются, если вы используете экземпляр, чтобы найти их.
candied_orange

111

Если вам нужен простой список размером 1:

List<String> strings = new ArrayList<String>(Collections.singletonList("A"));

Если вам нужен список из нескольких объектов:

List<String> strings = new ArrayList<String>();
Collections.addAll(strings,"A","B","C","D");

57

С Guava вы можете написать:

ArrayList<String> places = Lists.newArrayList("Buenos Aires", "Córdoba", "La Plata");

В Гуаве есть и другие полезные статические конструкторы. Вы можете прочитать о них здесь .


1
Я почти уверен, что вы можете сделать это только с java.util.Arraysтакими, как,List<String> names = Arrays.asList("Beckah", "Sam", "Michael");
Бекка

2
Метод @beckah Arrays.asLists создает объект типа List, а вопрос о создании ArrayList
Павел Адамский


34

Литералы коллекции не попали в Java 8, но можно использовать Stream API для инициализации списка в одну довольно длинную строку:

List<String> places = Stream.of("Buenos Aires", "Córdoba", "La Plata").collect(Collectors.toList());

Если вам необходимо убедиться , что ваш Listявляется ArrayList:

ArrayList<String> places = Stream.of("Buenos Aires", "Córdoba", "La Plata").collect(Collectors.toCollection(ArrayList::new));

34

С и выше, как предложено в JEP 269: Методы фабрики удобства для коллекций , это может быть достигнуто с помощью литералов коллекции теперь с -

List<String> list = List.of("A", "B", "C");

Set<String> set = Set.of("A", "B", "C");

Аналогичный подход будет применяться и к Map-

Map<String, String> map = Map.of("k1", "v1", "k2", "v2", "k3", "v3")

что аналогично предложению Collection Literals, как заявлено @coobird. Также уточняется в JEP -


альтернативы

Языковые изменения были рассмотрены несколько раз и отклонены:

Предложение монет проекта, 29 марта 2009 г.

Проект монетного предложения, 30 марта 2009 г.

JEP 186 дискуссия по лямбда-деву, январь-март 2014

Языковые предложения были отложены в предпочтении перед библиотечным предложением, как показано в этом сообщении.

Связанный: в чем смысл перегруженных методов фабрики удобства для коллекций в Java 9


31
import com.google.common.collect.ImmutableList;

....

List<String> places = ImmutableList.of("Buenos Aires", "Córdoba", "La Plata");

4
Я не хочу добавлять новую зависимость просто для этого.
Macarse

6
Это то же самое Collections.unmodifiableList(Arrays.asList("Buenos Aires", "Córdoba", "La Plata")), что и unmodifiableList(asList("Buenos Aires", "Córdoba", "La Plata"))при статическом импорте. Вам не нужны Google Коллекции для этого.
Кристоффер Хаммарстрем

9
Нет, это не то же самое. Поскольку ImmutableList документирует свою неизменность в типе результата, когда unmodifiableList маскирует его как обычный список.
Дэвид Пьер

2
Вместо неизменного коллекции Google также предлагают список изменяемых массивов: List <String> = Lists.newArrayList ("Буэнос-Айрес", "Кордова", "Ла-Плата");
Л. Холанда

3
Вы собираетесь передать это ImmutableListдругим методам, которые принимают List, и затем вы все равно потеряете эту документацию.
Кристофер Хаммарстрем

23

Вы можете создать фабричный метод:

public static ArrayList<String> createArrayList(String ... elements) {
  ArrayList<String> list = new ArrayList<String>();
  for (String element : elements) {
    list.add(element);
  }
  return list;
}

....

ArrayList<String> places = createArrayList(
  "São Paulo", "Rio de Janeiro", "Brasília");

Но это не намного лучше, чем ваш первый рефакторинг.

Для большей гибкости он может быть общим:

public static <T> ArrayList<T> createArrayList(T ... elements) {
  ArrayList<T> list = new ArrayList<T>();
  for (T element : elements) {
    list.add(element);
  }
  return list;
}

1
Посмотрите на исходный пост, он запрашивает инициализацию массива в одну строку , а не 7 дополнительных строк.
Л. Холанда

7
@ LeoHolanda: Создавать фабричные методы для каждой мелочи слишком много, я согласен. Но в зависимости от ситуации и от того, сколько раз будет использоваться этот метод, может иметь смысл создать его. Создание дополнительных слоев абстракции предназначено для устранения сложности путем создания более значимых методов, которые отражают намерения дизайнера.
Джордао

16

В Java 9 мы можем легко инициализировать ArrayListодну строку:

List<String> places = List.of("Buenos Aires", "Córdoba", "La Plata");

или

List<String> places = new ArrayList<>(List.of("Buenos Aires", "Córdoba", "La Plata"));

Этот новый подход Java 9 имеет много преимуществ по сравнению с предыдущими:

  1. Космическая эффективность
  2. неизменность
  3. Поток Сейф

Смотрите этот пост для более подробной информации -> В чем разница между List.of и Arrays.asList?


8

О самом компактном способе сделать это:

Double array[] = { 1.0, 2.0, 3.0};
List<Double> list = Arrays.asList(array);

8

Просто используйте приведенный ниже код следующим образом.

List<String> list = new ArrayList<String>() {{
            add("A");
            add("B");
            add("C");
}};

2
@bsd Вы можете использовать этот метод для объявления списка перед вводом любого метода. Таким образом, при определении переменных класса содержимое может быть добавлено в список без необходимости вызова метода для этого.
до

2
инициализации двойных скобок следует избегать, насколько это возможно. см .: stackoverflow.com/a/924326/760393
Рауль

8

С Eclipse Collections вы можете написать следующее:

List<String> list = Lists.mutable.with("Buenos Aires", "Córdoba", "La Plata");

Вы также можете более точно указать типы, а также то, являются ли они изменяемыми или неизменяемыми.

MutableList<String> mList = Lists.mutable.with("Buenos Aires", "Córdoba", "La Plata");
ImmutableList<String> iList = Lists.immutable.with("Buenos Aires", "Córdoba", "La Plata");

Вы также можете сделать то же самое с наборами и сумками:

Set<String> set = Sets.mutable.with("Buenos Aires", "Córdoba", "La Plata");
MutableSet<String> mSet = Sets.mutable.with("Buenos Aires", "Córdoba", "La Plata");
ImmutableSet<String> iSet = Sets.immutable.with("Buenos Aires", "Córdoba", "La Plata");

Bag<String> bag = Bags.mutable.with("Buenos Aires", "Córdoba", "La Plata");
MutableBag<String> mBag = Bags.mutable.with("Buenos Aires", "Córdoba", "La Plata");
ImmutableBag<String> iBag = Bags.immutable.with("Buenos Aires", "Córdoba", "La Plata");

Примечание: я являюсь коммиттером для Eclipse Collections.



7

(Должен быть комментарий, но слишком длинный, поэтому новый ответ). Как уже упоминалось, Arrays.asListметод имеет фиксированный размер, но это не единственная проблема с ним. Он также не очень хорошо обрабатывает наследование. Например, предположим, у вас есть следующее:

class A{}
class B extends A{}

public List<A> getAList(){
    return Arrays.asList(new B());
}

Вышеприведенное приводит к ошибке компилятора, потому что List<B>(то, что возвращается Arrays.asList) не является подклассом List<A>, даже если вы можете добавить объекты типа B к List<A>объекту. Чтобы обойти это, вам нужно сделать что-то вроде:

new ArrayList<A>(Arrays.<A>asList(b1, b2, b3))

Это, наверное, лучший способ сделать это, особенно. если вам нужен неограниченный список или вам нужно использовать наследование.


6

Вы можете использовать следующие утверждения:

Фрагмент кода:

String [] arr = {"Sharlock", "Homes", "Watson"};

List<String> names = Arrays.asList(arr);

Вы можете встроить первое выражение, чтобы иметь компактное решение:letters = Arrays.asList(new String[]{"A", "B", "C"});
Павел Репин

5

Как сказал Том :

List<String> places = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");

Но так как вы жаловались на то, что хотите ArrayList, вы должны сначала знать, что ArrayList является подклассом List, и вы можете просто добавить эту строку:

ArrayList<String> myPlaces = new ArrayList(places);

Хотя, это может заставить вас жаловаться на «производительность».

В этом случае мне не имеет смысла, почему, поскольку ваш список предопределен, он не был определен как массив (так как размер известен во время инициализации). И если это вариант для вас:

String[] places = {"Buenos Aires", "Córdoba", "La Plata"};

Если вам не нужны незначительные различия в производительности, вы также можете очень просто скопировать массив в ArrayList:

ArrayList<String> myPlaces = new ArrayList(Arrays.asList(places));

Хорошо, но в будущем вам понадобится не только название места, но и код страны. Предполагая, что это все еще предопределенный список, который никогда не изменится во время выполнения, тогда можно использовать enumнабор, который потребует повторной компиляции, если список потребуется изменить в будущем.

enum Places {BUENOS_AIRES, CORDOBA, LA_PLATA}

станет:

enum Places {
    BUENOS_AIRES("Buenos Aires",123),
    CORDOBA("Córdoba",456),
    LA_PLATA("La Plata",789);

    String name;
    int code;
    Places(String name, int code) {
      this.name=name;
      this.code=code;
    }
}

Enum имеет статический valuesметод, который возвращает массив, содержащий все значения enum в порядке их объявления, например:

for (Places p:Places.values()) {
    System.out.printf("The place %s has code %d%n",
                  p.name, p.code);
}

В этом случае, я думаю, вам не нужен ваш ArrayList.

PS Рандяа продемонстрировал еще один приятный способ, используя статический служебный метод Collections.addAll .


5

Java 9 имеет следующий метод для создания неизменяемого списка:

List<String> places = List.of("Buenos Aires", "Córdoba", "La Plata");

который легко адаптируется для создания изменяемого списка, если требуется:

List<String> places = new ArrayList<>(List.of("Buenos Aires", "Córdoba", "La Plata"));

Подобные методы доступны для Setи Map.


1
Хорошо, что вы явно сказали «неизменяемый список», а затем показали еще один пример изменяемого списка, потому что он дает понять, что и когда использовать.
Черит


4

Да, с помощью массивов вы можете инициализировать список массивов в одну строку,

List<String> strlist= Arrays.asList("aaa", "bbb", "ccc");

4

Вы можете использовать StickyListот Cactoos :

List<String> names = new StickyList<>(
  "Scott Fitzgerald", "Fyodor Dostoyevsky"
);


2

В Java вы не можете сделать

ArrayList<String> places = new ArrayList<String>( Arrays.asList("Buenos Aires", "Córdoba", "La Plata"));

Как было указано, вам нужно выполнить инициализацию в виде двойной скобки:

List<String> places = new ArrayList<String>() {{ add("x"); add("y"); }};

Но это может заставить вас добавить аннотацию @SuppressWarnings("serial") или создать серийный UUID, который раздражает. Кроме того, большинство форматировщиков кода развернут это в несколько операторов / строк.

В качестве альтернативы вы можете сделать

List<String> places = Arrays.asList(new String[] {"x", "y" });

но тогда вы можете сделать @SuppressWarnings("unchecked") .

Также в соответствии с Javadoc вы должны быть в состоянии сделать это:

List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");

Но я не могу заставить его скомпилировать с JDK 1.6.


5
Неправильно! Вы можете сделать первую строку, и это правильный ответ между прочим
Богемский

1
Collections.singletonList(messageBody)

Если вам нужно иметь список из одного элемента !

Коллекции из пакета java.util .


1

Лучший способ сделать это:

package main_package;

import java.util.ArrayList;


public class Stackkkk {
    public static void main(String[] args) {
        ArrayList<Object> list = new ArrayList<Object>();
        add(list, "1", "2", "3", "4", "5", "6");
        System.out.println("I added " + list.size() + " element in one line");
    }

    public static void add(ArrayList<Object> list,Object...objects){
        for(Object object:objects)
            list.add(object);
    }
}

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


1
Если вы преодолеете все трудности, вы можете сделать это методом шаблона вместо использования plain Object.
Роберт

1

Вот код от AbacusUtil

// ArrayList
List<String> list = N.asList("Buenos Aires", "Córdoba", "La Plata");
// HashSet
Set<String> set = N.asSet("Buenos Aires", "Córdoba", "La Plata");
// HashMap
Map<String, Integer> map = N.asMap("Buenos Aires", 1, "Córdoba", 2, "La Plata", 3);

// Or for Immutable List/Set/Map
ImmutableList.of("Buenos Aires", "Córdoba", "La Plata");
ImmutableSet.of("Buenos Aires", "Córdoba", "La Plata");
ImmutableSet.of("Buenos Aires", 1, "Córdoba", 2, "La Plata", 3);

// The most efficient way, which is similar with Arrays.asList(...) in JDK. 
// but returns a flexible-size list backed by the specified array.
List<String> set = Array.asList("Buenos Aires", "Córdoba", "La Plata");

Декларация: я разработчик AbacusUtil.


0

Для меня Arrays.asList () - лучший и удобный. Мне всегда нравится инициализировать этот путь. Если вы новичок в коллекциях Java, я бы хотел, чтобы вы ссылались на инициализацию ArrayList


Почему Arrays.asList () лучше, чем создание нового ArrayList в одну строку с add()методами?
Игорь Ганапольский

0

Почему бы не сделать простую служебную функцию, которая делает это?

static <A> ArrayList<A> ll(A... a) {
  ArrayList l = new ArrayList(a.length);
  for (A x : a) l.add(x);
  return l;
}

« ll» означает «буквальный список».

ArrayList<String> places = ll("Buenos Aires", "Córdoba", "La Plata");

0

интересно, что ни один вкладыш с другим перегруженным Stream::collect методом не указан

ArrayList<String> places = Stream.of( "Buenos Aires", "Córdoba", "La Plata" ).collect( ArrayList::new, ArrayList::add, ArrayList::addAll );

-1

На самом деле, это можно сделать в одну строку:

Arrays.asList(new MyClass[] {new MyClass("arg1"), new MyClass("arg2")})

3
Могу я спросить, что это добавляет к вопросу? Этот ответ уже покрыт несколько раз другими ответами.
Мистиаль

На самом деле это действительно плохое решение, так как создает РЕЗЮМЕ СПИСОК. Вы не сможете добавить что-либо еще в контейнер.
Atais
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.