Питання Ініціалізація ArrayList в одному рядку


Я хочу створити список параметрів для цілей тестування. Спочатку я зробив це:

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

Чи є кращий спосіб зробити це?


2163
2018-06-17 04:10


походження


Якщо це призначено для випробувань на агрегаті, спробуйте розібратись для розгону. Ви можете написати тестовий код під час тестування java-коду, а також використовувати його ArrasyList<String> places = ["Buenos Aires", "Córdoba", "La Plata"] - ripper234
У Java SE 7 ви можете замінити параметризований тип конструктора порожнім набором параметрів типу (<>): Карта <String, List <String >> myMap = new HashMap <> (); - Rose
Дивись також stackoverflow.com/questions/157944/create-arraylist-from-array - Christoffer Hammarström
використовувати ініціалізацію подвійної фіксації :) - Mohammad Reza Khatami
Stream.of ("val1", "val2"). Збирати (Collector.toList ()); // створює рішення ArrayList, Java8. - torina


Відповіді:


Насправді, ймовірно, "найкращий" спосіб ініціалізувати 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 який має ініціалізатор екземпляра, і цей клас створено просто для створення одного об'єкта - що, здається, трохи перекручує мене.

Що було б добре, якщо б Збірник литералов пропозиція за Монета проекту був прийнятий (він повинен був бути введений в Java 7, але, ймовірно, також не буде частиною Java 8):

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

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


1626
2018-06-17 04:13



Побачити stackoverflow.com/questions/924285 для отримання додаткової інформації про подвійну фіксацію ініціалізації, плюси і мінуси. - Eddie
@Eddie: Хороший заклик до посилання - одне речення про подвійну фіксацію ініціалізації недостатньо для його повного опису. - coobird
Працює тільки якщо ви не покладаються на автоматичний список боксу <Double> list = [1.0, 2.0, 3.0]; не вдається. - Richard B
Ну, просто показує - синаптичний цукор однієї людини - це ще один синтаксичний діабет. Я відстоюся від цих "альтернатив". - corsiKa
Оскільки дана відповідь є найвигіднішою та згаданою проектною монетою, я думаю, вам слід зателефонувати за те, що java 9 постачається зі списком (...) синтаксису: docs.oracle.com/javase/9/docs/api/java/util/List.html#of-E...- - Asaf


Було б простіше, якщо б ви просто оголосили це як 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"));

1734
2018-06-17 04:15



@Marcase: Чи не можете ви змінити свій клас, щоб використовувати список, а не ArrayList? - Lawrence Dol
Відповідно до моєї відповіді, якщо ви не використовуєте методи, специфічні для ArrayList, було б краще спроектувати зміну декларації до List. Вкажіть інтерфейси, а не додатки. - Christoffer Hammarström
@ Christoffer Hammarström: якщо він змінить декларацію до Перелік і використовує Список <String> places = Arrays.asList (...); він не зможе використати places.add ("blabla") - maks
Просто бути зрозумілим asList(...) повертає фіксований розмір List що вибухає на мутації операцій типу remove і clear, речі List договірні претензії на підтримку. Навіть якщо ви залишили декларацію як List, підвіконня потрібно використовувати List l = new ArrayList(asList(...)) для того, щоб отримати об'єкт, який не викидає Extensions, які підтримуються OperationNotSupported. Лісков Заміна Принцип кого? - Splash
@Сплеск: remove і clear є необов'язковими операціями в List, так asList(...) виконує контракт. Ніде OP не стверджує, що він повинен додавати більше елементів пізніше, приклад - лише a List що потрібно ініціалізувати за допомогою трьох елементів. - Christoffer Hammarström


Проста відповідь

У Java 8 або раніше:

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

Це дасть вам a List підтримується масивом, тому він не може змінювати довжину.
Але ви можете зателефонувати List.set, так що він все ще мінливий.


У Java 9:

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

Це дасть вам незмінне List, тому його не можна змінити.
Який саме ви хочете, в більшості випадків, коли ви переднесетаєте його.


Коротка відповідь

Ви можете зробити Arrays.asList ще коротше зі статичним імпортом:

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

Статичний імпорт:

import static java.util.Arrays.asList;  

Який будь-який сучасний IDE запропонує і автоматично зробить для вас.
Наприклад, у IntelliJ IDEA ви натискаєте Alt+Enter і виберіть Static import method....


Однак я не рекомендую скорочення Java 9 List.of метод, тому що просто of стає заплутаним.
List.of вже досить короткий і добре читається.


Використовуючи Streamс

Чому це повинно бути а List?
З Java 8 або пізнішої версії ви можете використовувати a Stream що є більш гнучким:

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

Ви можете об'єднати Streamс:

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

Або ви можете піти з Stream до a List:

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

Але бажано, просто використовуйте Stream не збираючи його до а List.


Якщо ви дійсно конкретно потрібно а java.util.ArrayList

(Ви, напевно, цього не робите.)
Цитувати JEP 269 (наголос мій):

Є а маленький набір випадків використання для ініціалізації мінливого екземпляра збірки з заданим набором значень. Зазвичай переважно, щоб ці заздалегідь задані значення знаходилися в незмінному зборі, а потім ініціалізувати змінну колекцію за допомогою конструктора копії.


Якщо ти хочеш обидва передпопуляції ArrayList  і додати до нього пізніше (чому?), скористайтеся

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

або в Java 9:

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

або використовуючи Stream:

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

Але знову ж таки краще просто скористатись Stream безпосередньо замість того, щоб зібрати його до a List.


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

Ви сказали, що ви оголосили цей список як ArrayList у вашому коді, але ви повинні робити це лише тоді, коли ви використовуєте якийсь член ArrayList це не в List.

Що ви, швидше за все, не робите.

Зазвичай ви повинні просто оголосити змінні самим загальним інтерфейсом, який ви збираєтеся використовувати (наприклад, Iterable, Collection, або List) і ініціалізувати їх з конкретною реалізацією (наприклад, ArrayList, LinkedList або Arrays.asList())

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

Наприклад:

// Iterable if you just need iteration, for (String s : strings):
Iterable<String> strings = new ArrayList<>();   

// Collection if you also need .size() or .stream():
Collection<String> strings = new ArrayList<>(); 

// List if you also need .get(index):
List<String> strings = new ArrayList<>();       

// Don't declare a specific list implementation
// unless you're sure you need it:
ArrayList<String> strings = new ArrayList<>();  // You don't need ArrayList

Іншим прикладом завжди буде оголошення змінної a InputStream хоча це зазвичай а FileInputStream або a BufferedInputStream, тому що одного дня незабаром ти або хтось інший хоче використовувати якийсь інший вид InputStream.


582
2017-09-09 12:33



Спасибі вам колись так багато. Я намагався опустити "статичний" імпорт у моєму коді, але компілятор не мав жодного з них. Чому статичність потрібна для роботи коду? - jollyroger
@веселий Роджер: Arrays.asList є статичним методом. Побачити docs.oracle.com/javase/1.5.0/docs/guide/language/... - Christoffer Hammarström
@ ChristofferHammarström У цьому випадку мій початківець розум розповідає мені, що статичний імпорт має сильну схожість із глобальними змінами та небезпеками, які стосуються такого використання. Чи є це припущення правильним, і чи є також підставою для подібної відповіді, що наведена вище, отримання більшої кількості голосів? - jollyroger
Якщо ви не бажаєте статичного імпорту, ви також можете визначити повний шлях до статичного методу asList, як так: Список <String> strings = java.util.Arrays.asList ("", ""); - Geert Weening
Або ви можете використовувати імпорт java.util.Arrays; і масиви.асписок ("", ""); Вам не потрібно використовувати статичний імпорт. Вам не потрібно використовувати повний шлях. Статичні методи не піклуються про імпорт. Вони просто дратуються, якщо ви використовуєте екземпляр, щоб знайти їх. - candied_orange


Якщо вам потрібен простий список розміру 1:

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

Якщо вам потрібен список декількох об'єктів:

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

100
2017-08-30 04:33





З Гуава ви можете написати:

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

У Гуава також є й інші корисні статичні конструктори. Ви можете прочитати про них тут.


52
2017-07-29 13:24



Я впевнений, що ви можете зробити це просто java.util.Arrays як от, List<String> names = Arrays.asList("Beckah", "Sam", "Michael"); - beckah
Метод @beckah Arrays.asLists створює об'єкт типу List, а питання про створення ArrayList - Paweł Adamski
Цей метод насправді не дуже корисний і, швидше за все, буде застарілим в майбутньому. - shmosel


Колекція літералів не перетворила його на Java 8, але можна використовувати API Stream для ініціалізації списку в одній досить довгій рядку:

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

32
2018-04-03 23:21





import com.google.common.collect.ImmutableList;

....

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

26
2018-05-12 13:14



Я не хочу додавати нову залежність, щоб це зробити. - Macarse
Це те ж саме, що і Collections.unmodifiableList(Arrays.asList("Buenos Aires", "Córdoba", "La Plata")), який стає unmodifiableList(asList("Buenos Aires", "Córdoba", "La Plata")) з статичним імпортом. Для цього Вам не потрібні Колекції Google. - Christoffer Hammarström
Ні, це не те ж саме. Оскільки ImmutableList документує його незмінність у типі результату, коли незмінний список замаскує його як звичайний список. - David Pierre
Замість того, що незмінна, колекції Google також пропонують змінний список масивів: List <String> = Lists.newArrayList ("Буенос-Айрес", "Кордова", "Ла Плата"); - L. Holanda
Ви збираєтеся це пройти ImmutableList до інших методів, які приймають a List, а потім ви втратили цю документацію в будь-якому випадку. - Christoffer Hammarström


Ви можете створити заводський метод:

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;
}

22
2018-05-04 00:57



Поверніться до оригінального повідомлення, він запитує ініціалізацію масиву в одна лінія, а не 7 додаткових рядків. - L. Holanda
@LeoHolanda: Створення фабричних методів для кожної дрібниці дуже багато, я згоден. Але залежно від на ситуацію, і на кількість разів, коли цей метод буде використаний, може бути сенс його створити. Створення додаткових абстрактних шарів має на увазі видалити складності, створюючи більше значущий методи, які фіксують намір дизайнера. - Jordão


З Java 9, як запропоновано в JDK Enhancement Proposal - 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")

яка схожа на Збірник литералов пропозиція як зазначив @coobird також. Далі пояснюється в документі JEP -


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

Зміни мови були розглянуті кілька разів і відхилено:

Проект монети пропозиції, 29 березня 2009 року 

Проект монети пропозиції, 30 березня 2009 року 

Обговорення JEP 186 на lambda-dev, січень-березень 2014 року

Мова   пропозиції були відкинуті на відміну від бібліотечної пропозиції як   узагальнено в цьому повідомлення.

Ланцюг читав приблизно так само ~> Яка перевага перевантажена заводськими методами


17
2018-02-02 17:36





У 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?


11
2017-10-06 01:16





Найбільш компактним способом це зробити є:

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

7
2017-12-15 11:44