Domanda Inizializzazione di una lista array in una riga


Voglio creare un elenco di opzioni a scopo di test. All'inizio, l'ho fatto:

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

Quindi ho rifattorizzato il codice come segue:

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

C'è un modo migliore per farlo?


2157
2018-06-17 04:10


origine


risposte:


In realtà, probabilmente il modo "migliore" per inizializzare il ArrayList è il metodo che hai scritto, in quanto non ha bisogno di crearne uno nuovo List in ogni modo:

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

Il problema è che c'è un bel po 'di digitazione necessaria per riferirsi a questo list esempio.

Esistono alternative, come la creazione di una classe interna anonima con un inizializzatore di istanza (noto anche come "inizializzazione doppia coppia"):

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

Tuttavia, non mi piace troppo quel metodo perché quello che si finisce è una sottoclasse di ArrayList che ha un inizializzatore di istanze, e quella classe è creata solo per creare un oggetto - che mi sembra un po 'eccessivo.

Quello che sarebbe stato carino era se il Raccolta Letterale proposta per Progetto Coin è stato accettato (era previsto che fosse introdotto in Java 7, ma probabilmente non fa parte di Java 8):

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

Sfortunatamente non ti aiuterà qui, poiché inizializzerà un immutabile List piuttosto che un ArrayListe inoltre, non è ancora disponibile, se mai lo sarà.


1624
2018-06-17 04:13



Sarebbe più semplice se tu lo dichiarassi come a List - deve essere un ArrayList?

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

O se hai un solo elemento:

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

Questo significherebbe questo places è immutabile (provare a cambiarlo causerà un UnsupportedOperationException eccezione da lanciare).

Per fare una lista mutabile che è concreta ArrayList puoi creare un ArrayList dalla lista immutabile:

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

1724
2018-06-17 04:15



La risposta semplice

In Java 8 o precedenti:

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

Questo ti darà un List supportato dall'array, quindi non può cambiare la lunghezza.
Ma puoi chiamare List.set, quindi è ancora mutevole.


In Java 9:

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

Questo ti darà un immutabile List, quindi non può essere cambiato.
Qual è quello che vuoi nella maggior parte dei casi in cui lo stai prepopolando.


La risposta più breve

Tu puoi fare Arrays.asList ancora più corto con un'importazione statica:

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

L'importazione statica:

import static java.util.Arrays.asList;  

Quale IDE moderno suggerirà e automaticamente farà per te.
Ad esempio in IntelliJ IDEA si preme Alt+Enter e selezionare Static import method....


Tuttavia, non consiglio di abbreviare Java 9 List.of metodo, perché avendo giusto of diventa confuso.
List.of è già abbastanza corto e legge bene.


utilizzando StreamS

Perché deve essere un List?
Con Java 8 o versioni successive è possibile utilizzare a Stream che è più flessibile:

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

Puoi concatenare StreamS:

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

Oppure puoi andare da a Stream a a List:

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

Ma preferibilmente, usa semplicemente il Stream senza raccoglierlo in a List.


Se tu veramente specificamente bisogno di java.util.ArrayList

(Probabilmente no.)
Per citare JEP 269 (sottolineatura mia):

C'è un piccolo set di casi d'uso per inizializzare un'istanza di raccolta mutabile con un insieme predefinito di valori. Di solito è preferibile avere quei valori predefiniti in una collezione immutabile e quindi inizializzare la raccolta mutabile tramite un costruttore di copie.


Se lo desidera entrambi prepopolare un ArrayList  e aggiungere in seguito (perché?), utilizzare

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

o in Java 9:

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

o usando Stream:

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

Ma ancora, è meglio usare semplicemente il Stream direttamente invece di raccoglierlo in a List.


Programma per interfacce, non per implementazioni

Hai detto di aver dichiarato la lista come un ArrayList nel tuo codice, ma dovresti farlo solo se stai usando qualche membro di ArrayList non è in List.

Che probabilmente non stai facendo.

Di solito dovresti semplicemente dichiarare le variabili tramite l'interfaccia più generale che intendi utilizzare (ad es. Iterable, Collection, o List) e inizializzarli con l'implementazione specifica (ad es. ArrayList, LinkedList o Arrays.asList()).

Altrimenti si limiterà il codice a quel tipo specifico e sarà più difficile cambiarlo quando lo si desidera.

Per esempio:

// 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

Un altro esempio sarebbe sempre dichiarando la variabile an InputStream anche se di solito è un FileInputStream o a BufferedInputStream, perché un giorno presto tu o qualcun altro vorrà usare qualche altro tipo di InputStream.


580
2017-09-09 12:33



Se hai bisogno di un semplice elenco di dimensioni 1:

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

Se hai bisogno di un elenco di diversi oggetti:

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

100
2017-08-30 04:33



Con Guaiava tu puoi scrivere:

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

In Guava ci sono anche altri costruttori statici utili. Puoi leggere su di loro Qui.


52
2017-07-29 13:24



I letterali di raccolta non sono stati convertiti in Java 8, ma è possibile utilizzare l'API di streaming per inizializzare un elenco in una riga piuttosto lunga:

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

Se hai bisogno di assicurarti che il tuo List è un 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



Potresti creare un metodo di fabbrica:

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

Ma non è molto meglio del tuo primo refactoring.

Per una maggiore flessibilità, può essere generico:

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



Con Java 9, come suggerito in Proposta di miglioramento JDK - 269, questo potrebbe essere ottenuto usando letterali di raccolta ora come -

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

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

Anche un approccio simile si applicherebbe a Map anche -

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

che è simile a Raccolta Letterale proposta come dichiarato da @coobird pure. Ulteriormente chiarito anche nel documento JEP -


alternative

Le modifiche alla lingua sono state considerate più volte e rifiutate:

Progetto Coin Proposal, 29 marzo 2009 

Progetto Coin Proposal, 30 marzo 2009 

Discussione di JEP 186 su lambda-dev, gennaio-marzo 2014

La lingua   le proposte sono state accantonate preferibilmente a una proposta basata sulla biblioteca   riassunto in questo Messaggio.

Leggere incatenato sullo stesso ~> Qual è il punto di Metodi Convenience Factory sovraccaricati


17
2018-02-02 17:36



In Java 9 possiamo inizializzare facilmente un ArrayList in una sola riga:

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

o

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

Questo nuovo approccio di Java 9 presenta molti vantaggi rispetto ai precedenti:

  1. Efficienza dello spazio
  2. Immutabilità
  3. Filo sicuro

Vedi questo post per maggiori dettagli -> Qual è la differenza tra List.of e Arrays.asList?


11
2017-10-06 01:16



Il modo più compatto per farlo è:

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

7
2017-12-15 11:44