HOWTO · Java

Copia ArrayList in Java

Questo articolo descrive vari metodi per copiare un ArrayList in un'altra lista in Java.

In questa pagina

Per copiare un ArrayList in una lista separata in Java, usa il costruttore di copia se vuoi creare una nuova lista inizializzata con gli elementi della sorgente. Puoi usare anche addAll(), uno stream o clone(). Questi approcci copiano la struttura della lista, non gli oggetti che contiene: se un elemento è mutabile, entrambe le liste continuano a fare riferimento allo stesso oggetto. Gli esempi usano gli stessi nomi, così puoi confrontare come ciascun metodo crea o riempie la destinazione.

Come scegliere un metodo per copiare un ArrayList

Scegli new ArrayList<>(source) per creare nel modo più diretto una nuova lista a partire da una raccolta esistente. Usa destination.addAll(source) quando hai già una destinazione e vuoi aggiungervi in coda gli elementi della sorgente; svuotala prima solo se vuoi sostituirne il contenuto. Uno stream è utile quando si integra già in una pipeline di trasformazione, ma Collectors.toList() garantisce un List, non nello specifico un ArrayList. Se il codice richiede quel tipo concreto, passa il risultato al costruttore di copia. Anche clone() è un’opzione per una copia superficiale, ma il tipo restituito Object richiede un cast.

Una copia superficiale ha una struttura indipendente: aggiungere o rimuovere un elemento da una lista non modifica la dimensione né l’ordine dell’altra. I riferimenti agli elementi, però, sono condivisi. Per esempio, se copi una lista di oggetti mutabili StringBuilder e poi chiami setLength(0) su un oggetto ottenuto dalla copia, anche la lista sorgente riflette la modifica. Per copiare gli elementi mutabili in modo indipendente, crea anche nuovi oggetti elemento: nessuno dei quattro metodi seguenti esegue questa copia più profonda. Le stringhe negli esempi sono immutabili, perciò permettono di confrontare facilmente le operazioni sulle liste senza suggerire che venga copiata anche la mutabilità degli elementi.

Copiare un ArrayList con il costruttore di copia

Il costruttore che accetta una raccolta inizializza un nuovo ArrayList con gli elementi della sorgente, rispettandone l’ordine di iterazione. È la scelta predefinita più concisa quando ti serve un’altra lista e non devi trasformare gli elementi. La sorgente resta una lista distinta, mentre i riferimenti agli eventuali elementi mutabili sono condivisi.

Esegui questo esempio:

Il codice e le etichette o gli output visibili in questa sezione restano in inglese.

import java.util.ArrayList;

public class CopyArrayList {
  public static void main(String[] args) {
    ArrayList<String> names1 = new ArrayList<>();
    names1.add("Alan");
    names1.add("Alex");
    names1.add("Bob");
    names1.add("Bryan");
    names1.add("Cathy");
    names1.add("Drake");

    ArrayList<String> names2 = new ArrayList<>(names1);
    names2.forEach(System.out::println);
  }
}

Copiare gli elementi con addAll()

addAll() aggiunge ogni elemento della raccolta fornita in fondo alla destinazione e restituisce un valore che indica se la destinazione è cambiata. Non sostituisce il contenuto esistente. Per creare una copia da zero, parti da una destinazione vuota, come nell’esempio seguente. Se passi una destinazione già popolata, i suoi elementi restano all’inizio e quelli della sorgente vengono aggiunti dopo. Anche questa operazione crea una copia superficiale: le liste sono distinte, ma gli elementi mutabili sono condivisi.

Il codice e le etichette o gli output visibili in questa sezione restano in inglese.

import java.util.ArrayList;

public class CopyArrayList {
  public static void main(String[] args) {
    ArrayList<String> names1 = new ArrayList<>();
    names1.add("Alan");
    names1.add("Alex");
    names1.add("Bob");
    names1.add("Bryan");
    names1.add("Cathy");
    names1.add("Drake");

    ArrayList<String> names2 = new ArrayList<>();
    names2.addAll(names1);
    names2.forEach(System.out::println);
  }
}

Copiare un ArrayList con uno stream

Uno stream può raccogliere gli elementi della sorgente in una lista, ma Collectors.toList() non garantisce una particolare implementazione. Non eseguire il cast del risultato a ArrayList: il valore restituito è specificato soltanto come List, quindi il cast non è sicuro. Creando un ArrayList a partire dalla raccolta ottenuta, specifichi esplicitamente il tipo concreto. Anche in questo caso vengono copiati i riferimenti, non gli elementi mutabili.

Il codice e le etichette o gli output visibili in questa sezione restano in inglese.

import java.util.ArrayList;
import java.util.stream.Collectors;

public class CopyArrayList {
  public static void main(String[] args) {
    ArrayList<String> names1 = new ArrayList<>();
    names1.add("Alan");
    names1.add("Alex");
    names1.add("Bob");
    names1.add("Bryan");
    names1.add("Cathy");
    names1.add("Drake");

    ArrayList<String> names2 = new ArrayList<>(
        names1.stream().collect(Collectors.toList()));
    names2.forEach(System.out::println);
  }
}

Copiare un ArrayList con clone()

ArrayList.clone() crea una copia superficiale e ha tipo di ritorno dichiarato Object. Per usare il risultato come ArrayList, esegui un cast; poiché il tipo generico degli elementi è cancellato, il cast non è verificato e normalmente genera un avviso del compilatore. In questo esempio, però, l’annotazione @SuppressWarnings("unchecked") applicata alla dichiarazione sopprime tale avviso. Limita il cast a una lista che sai contenere il tipo di elementi previsto. Se vuoi evitare il cast e l’avviso, preferisci il costruttore di copia.

Il codice e le etichette o gli output visibili in questa sezione restano in inglese.

import java.util.ArrayList;

public class CopyArrayList {
  public static void main(String[] args) {
    ArrayList<String> names1 = new ArrayList<>();
    names1.add("Alan");
    names1.add("Alex");
    names1.add("Bob");
    names1.add("Bryan");
    names1.add("Cathy");
    names1.add("Drake");

    @SuppressWarnings("unchecked")
    ArrayList<String> names2 = (ArrayList<String>) names1.clone();
    names2.forEach(System.out::println);
  }
}