Conversione di una raccolta in ArrayList in Java

1. Panoramica

La conversione di raccolte Java da un tipo a un altro è un'attività di programmazione comune. In questo tutorial, convertiremo qualsiasi tipo di Collection in un ArrayList .

In tutto il tutorial, assumeremo di avere già una raccolta di oggetti Foo . Da lì, creeremo un ArrayList utilizzando vari approcci.

2. Definire il nostro esempio

Ma prima di continuare, modelliamo il nostro input e output.

La nostra fonte potrebbe essere qualsiasi tipo di raccolta, quindi la dichiareremo utilizzando l' interfaccia della raccolta :

Collection srcCollection; 

Dobbiamo produrre un ArrayList con lo stesso tipo di elemento:

ArrayList newList;

3. Utilizzo del costruttore ArrayList

Il modo più semplice per copiare una raccolta in una nuova raccolta è utilizzare il suo costruttore.

Nella nostra precedente guida ad ArrayList, abbiamo appreso che il costruttore di ArrayList può accettare un parametro di raccolta:

ArrayList newList = new ArrayList(srcCollection);
  • Il nuovo ArrayList contiene una copia superficiale degli elementi Foo nella raccolta di origine.
  • L'ordine è lo stesso della raccolta di origine.

La semplicità del costruttore lo rende un'ottima opzione nella maggior parte degli scenari.

4. Utilizzo dell'API Streams

Ora, sfruttiamo l'API Streams per creare un ArrayList da una raccolta esistente :

ArrayList newList = srcCollection.stream().collect(toCollection(ArrayList::new));

In questo frammento:

  • Prendiamo il flusso dalla raccolta di origine e applichiamo l' operatore collect () per creare un elenco
  • Specifichiamo ArrayList :: new per ottenere il tipo di elenco che vogliamo
  • Questo codice produrrà anche una copia superficiale.

Se non fossimo preoccupati per il tipo esatto di elenco , potremmo semplificare:

List newList = srcCollection.stream().collect(toList());

Notare che toCollection () e toList () vengono importati staticamente dai servizi di raccolta . Per saperne di più, fai riferimento alla nostra guida sui collezionisti di Java 8.

5. Copia profonda

Prima abbiamo menzionato le "copie superficiali". Con questo, intendiamo che gli elementi nel nuovo elenco sono esattamente le stesse istanze Foo che esistono ancora nella raccolta sorgente. Pertanto, abbiamo copiato i Foo nella newList per riferimento.

Se modifichiamo il contenuto di un'istanza Foo in una delle raccolte, la modifica si rifletterà in entrambe le raccolte . Quindi, se vogliamo modificare gli elementi in una delle raccolte senza modificare l'altra, dobbiamo eseguire una "copia completa".

Per copiare in profondità un Foo , creiamo un'istanza Foo completamente nuova per ogni elemento . Di conseguenza, tutti i campi Foo devono essere copiati nelle nuove istanze.

Definiamo la nostra classe Foo in modo che sappia come copiarsi in profondità:

public class Foo { private int id; private String name; private Foo parent; public Foo(int id, String name, Foo parent) { this.id = id; this.name = name; this.parent = parent; } public Foo deepCopy() { return new Foo( this.id, this.name, this.parent != null ? this.parent.deepCopy() : null); } }

Qui possiamo vedere che i campi id e name sono int e String . Questi tipi di dati vengono copiati in base al valore. Quindi, possiamo semplicemente assegnarli entrambi.

Il campo genitore è un altro Foo , che è una classe. Se Foo venisse mutato, qualsiasi codice che condivide quel riferimento sarebbe influenzato da queste modifiche. Dobbiamo copiare in profondità il campo genitore .

Ora possiamo tornare alla nostra conversione ArrayList . Abbiamo solo bisogno dell'operatore della mappa per inserire la copia profonda nel flusso:

ArrayList newList = srcCollection.stream() .map(foo -> foo.deepCopy()) .collect(toCollection(ArrayList::new));

Possiamo modificare il contenuto di una delle raccolte senza influire sull'altra.

Una copia completa può essere un processo lungo a seconda del numero di elementi e della profondità dei dati. L'utilizzo di un flusso parallelo qui può fornire un aumento delle prestazioni se necessario.

6. Controllo dell'ordine degli elenchi

Per impostazione predefinita, il nostro flusso fornirà gli elementi al nostro ArrayList nello stesso ordine in cui si trovano nella raccolta di origine.

Se vogliamo cambiare tale ordine , potremmo applicare l' operatore Sort () allo stream . Per ordinare i nostri oggetti Foo per nome:

ArrayList newList = srcCollection.stream() .sorted(Comparator.comparing(Foo::getName)) .collect(toCollection(ArrayList::new));

Possiamo trovare ulteriori dettagli sull'ordinamento degli stream in questo tutorial precedente.

7. Conclusione

Il costruttore ArrayList è un modo efficace per ottenere il contenuto di una raccolta in un nuovo ArrayList .

However, if we need to tweak the resulting list, the Streams API provides a powerful way to modify the process.

The code used in this article can be found in its entirety over on GitHub.