Вопрос-ответ

Initialization of an ArrayList in one line

Инициализация списка массивов в одной строке

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

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"));

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

Переведено автоматически
Ответ 1

Было бы проще, если бы вы просто объявили это как 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"));

И импортируйте правильный пакет:

import java.util.Arrays;
Ответ 2

На самом деле, вероятно, "лучшим" способом инициализации 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, у которого есть инициализатор экземпляра, и этот класс создан только для создания одного объекта - мне это кажется немного излишним.

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

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

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

Ответ 3

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

Java 9 или более поздней версии:

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

List.of(...) даст вам неизменяемый List, поэтому его нельзя изменить.

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

Это не позволяет использовать null элементы.

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

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

Arrays.asList(...) выдаст вам List*, подкрепленный массивом, поэтому он не может изменять длину.

Но вы можете вызвать List.set(...), так что это все равно изменяемый.

Это действительно допускает null элементы.

* Подробности реализации: Это частный вложенный класс внутри java.util.Arrays с именем ArrayList,
который отличается от java.util.ArrayList класса, хотя их простые имена совпадают.

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

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

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

Любая современная IDE * предложит и сделает это за вас.

Я не рекомендую статически импортировать List.of метод как just of , потому что это сбивает с толку.

* Например, в IntelliJ IDEA вы нажимаете Alt+Enter и выбираете Static import method...

Использование Streams

Почему это должен быть aList?
В Java 8 или более поздней версии вы можете использовать a 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;
...
var strings = Stream.of("foo", "bar", "baz").toList(); // Java 16

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

Но предпочтительно просто использовать Stream не собирая его в List.

Если вам конкретно нужен java.util.ArrayList*

Если вы хотите одновременно предварительно заполнить ArrayList и дополнить его впоследствии, используйте

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

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

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

или с помощью Stream:

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

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

Затем вы можете добавить к нему после построения:

strings.add("baz");

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

*Вам, вероятно, конкретно не нужен ArrayList. Цитирую JEP 269:


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


(выделено мной)

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

Вы сказали, что объявили список как 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 random access, .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
}

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

Ответ 4

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

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

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

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