Инициализация списка массивов в одной строке
Я хотел создать список опций для целей тестирования. Сначала я сделал это:
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...
Использование Stream
s
Почему это должен быть aList
?
В Java 8 или более поздней версии вы можете использовать a Stream
который является более гибким:
Stream<String> strings = Stream.of("foo", "bar", "baz");
Вы можете объединить Stream
s:
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");