Java List: Guida completa per principianti e sviluppatori

目次

1. Introduzione

Qual è l’importanza di List in Java?

Nella programmazione Java, “List” è una struttura dati che compare molto frequentemente. Soprattutto in situazioni in cui si desidera gestire più valori insieme, è più flessibile e più semplice da usare rispetto agli array, rendendola molto apprezzata in molti scenari pratici.
“List” è un’interfaccia fondamentale nel Java Collections Framework e fornisce un meccanismo per gestire varie situazioni attraverso diverse classi di implementazione come ArrayList e LinkedList. La possibilità di eseguire operazioni come aggiungere, eliminare, cercare e aggiornare dati in modo intuitivo è uno dei motivi per cui List è così prediletta.

Scopo e pubblico di riferimento di questo articolo

Questo articolo spiegherà in modo sistematico “Java List”, dalle basi agli argomenti avanzati, in modo chiaro per i principianti. Il pubblico principale è il seguente:

  • Chi sta iniziando a imparare Java e non sa ancora come usare List
  • Chi vuole comprendere chiaramente la differenza tra Array e List
  • Chi è indeciso nella scelta tra ArrayList e LinkedList
  • Chi desidera rivedere le basi prima di utilizzare List in pratica

Al termine della lettura, l’obiettivo è che tu abbia una solida comprensione dei concetti fondamentali, dei metodi di implementazione e delle operazioni specifiche di List in Java, così da poter programmare con sicurezza.
Nel capitolo successivo inizieremo spiegando la parte base, “Che cos’è List?”, passo dopo passo.

2. Che cos’è List?

Panoramica e caratteristiche di List

“List” in Java è un’interfaccia di collezione che mantiene gli elementi in una sequenza ordinata. Le sue caratteristiche principali sono che l’ordine di inserimento degli elementi viene preservato e che gli elementi individuali possono essere accessibili tramite un indice (a partire da 0).
List fa parte del Collections Framework e presenta le seguenti proprietà:

  • Consente elementi duplicati
  • Permette di ottenere, aggiornare e rimuovere elementi specificando un indice
  • Può aumentare o diminuire dinamicamente il numero di elementi (a differenza degli array, non ha dimensione fissa)

Ciò consente una manipolazione dei dati flessibile ed è molto utilizzato nel lavoro pratico.

Differenza rispetto agli Array

In Java, gli array (come int[] o String[]) esistono anch’essi come mezzo per contenere più valori, ma presentano diverse differenze rispetto a List.

Comparison ItemArrayList
Changing number of elementsNot possible (fixed-size)Possible (can increase/decrease dynamically)
Provided functionalityMinimal operations (indexed access, length retrieval)Rich methods (add, remove, contains, etc.)
TypeCan handle primitive typesObject types only (wrapper classes required)
Type safetyArrays checked at compile timeCan strictly specify type with Generics

Perciò, List è una collezione più flessibile e ricca di funzionalità, risultando più pratica degli array in molte situazioni.

Interfaccia List e le sue classi di implementazione

Quando si utilizza List in Java, di solito si dichiara una variabile tramite l’interfaccia List e si crea un’istanza con una classe specifica (classe di implementazione). Le classi di implementazione più rappresentative sono:

  • ArrayList – Struttura simile a un array, consente un accesso rapido. Ottimale per la ricerca di dati e l’accesso casuale.
  • LinkedList – Implementata con una struttura a lista doppiamente collegata. Veloce per inserimenti e cancellazioni, adatta a liste con operazioni frequenti.
  • Vector – Simile ad ArrayList ma leggermente più pesante perché thread‑safe. Oggi poco usato.

In generale, ArrayList è la più comunemente impiegata, salvo casi particolari. È consigliabile scegliere quella più adatta in base al confronto di prestazioni descritto più avanti, a seconda del caso d’uso.

3. Uso di base di List

Questa sezione spiega le operazioni di base quando si utilizza List in Java, passo dopo passo. Qui useremo principalmente ArrayList come esempio per introdurre le operazioni rappresentative di List.

Dichiarazione e inizializzazione di List

Per prima cosa, vediamo la dichiarazione e l’inizializzazione di base di una List usando ArrayList.

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();
    }
}

È pratica comune dichiarare una variabile con l’interfaccia List e istanziarla con ArrayList. I generics vengono usati per specificare il tipo da memorizzare (qui, String).

Aggiungere Elementi (add)

Per aggiungere elementi a una List, usa il metodo add().

fruits.add("apple");
fruits.add("banana");
fruits.add("orange");

Questo aggiunge tre elementi alla List in sequenza. La List preserva l’ordine di aggiunta.

Ottenere Elementi (get)

Per ottenere un elemento a un indice specificato, usa get(int index).

System.out.println(fruits.get(0)); // "apple" will be displayed

Nota che gli indici partono da 0.

Aggiornare Elementi (set)

Per aggiornare un elemento in una certa posizione, usa set(int index, E element).

fruits.set(1, "grape"); // The second element "banana" is replaced with "grape"

Rimuovere Elementi (remove)

Puoi anche rimuovere elementi tramite un indice specifico o l’elemento stesso.

fruits.remove(0);           // Removes the first element
fruits.remove("orange");    // Removes "orange" (only the first match)

Ottenere la Dimensione della List (size)

Il numero corrente di elementi può essere ottenuto con il metodo size().

System.out.println(fruits.size()); // Returns 2, etc.

Verificare l’Esistenza di un Elemento (contains)

Per verificare se un elemento specifico è incluso nella List, usa contains().

if (fruits.contains("grape")) {
    System.out.println("grape is present");
}

Riepilogo: Elenco delle Operazioni Base più Usate

OperationMethod ExampleDescription
Additionadd("element")Adds to the end
Retrievalget(index)References an element
Updateset(index, new element)Changes the element at the specified position
Removalremove(index/element)Removes the specified element
Get Sizesize()Gets the number of elements
Check Existencecontains("element")Checks if a specific element exists

4. Esempi di Operazioni su List

In questo capitolo introdurremo esempi pratici di operazioni usando la List di Java. Ci sono molte situazioni in cui si desidera elaborare gli elementi di una lista in modo sequenziale, e qui copriremo i metodi rappresentativi usando for loop, enhanced for loop e Stream API.

Iterazione usando un ciclo for

Il metodo più basilare è recuperare gli elementi usando un indice all’interno di un ciclo for.

List<String> fruits = new ArrayList<>();
fruits.add("apple");
fruits.add("banana");
fruits.add("orange");

for (int i = 0; i < fruits.size(); i++) {
    System.out.println(fruits.get(i));
}

Questo metodo consente un controllo fine usando l’indice. Per esempio, è efficace quando vuoi elaborare solo gli elementi con indici pari.

Iterazione usando un ciclo for-each (enhanced for loop)

Se vuoi elaborare tutti gli elementi in sequenza senza preoccuparti dell’indice, il ciclo for-each è comodo.

for (String fruit : fruits) {
    System.out.println(fruit);
}

La sintassi è semplice e facile da leggere, rendendola uno dei metodi più comunemente usati. È sufficiente per elaborazioni semplici.

Iterazione usando Lambda Expressions e Stream API

A partire da Java 8, puoi anche usare la sintassi con Stream API e lambda expressions.

fruits.stream().forEach(fruit -> System.out.println(fruit));

Il punto di forza di questa notazione è che più processi possono essere concatenati. Per esempio, puoi facilmente filtrare e poi stampare gli elementi in base a criteri specifici.

fruits.stream()
      .filter(fruit -> fruit.contains("a"))
      .forEach(System.out::println);

In questo esempio, stampa solo i frutti che contengono “a”. È particolarmente consigliato per chi vuole abituarsi alla programmazione in stile funzionale.

Scegliere il Metodo Giusto

MethodAdvantagesSuitable Situations
Regular for loopAllows index controlProcessing that requires element numbers
Enhanced for loopSimple and easy to read syntaxSimple iteration processing
Stream APIStrong for conditional and chained processingWhen combining filtering, mapping, and reduction

5. Differenze e Uso di ArrayList e LinkedList

Le classi rappresentative che implementano l’interfaccia List di Java sono ArrayList e LinkedList. Entrambe possono essere usate come List allo stesso modo, ma presentano differenze nella struttura interna e nelle caratteristiche di prestazione, quindi è importante usarle in modo appropriato nelle situazioni giuste.

Caratteristiche e Casi d’Uso Adeguati di ArrayList

ArrayList utilizza internamente un array dinamico (array ridimensionabile).

Caratteristiche Principali:

  • Molto veloce per l’accesso casuale (basato su indice)
  • L’aggiunta di elementi alla fine della lista è veloce (media O(1))
  • Inserimento e rimozione al centro sono più lenti (O(n))

Situazioni adatte:

  • Situazioni in cui la ricerca (get()) è frequente
  • Situazioni in cui il numero di elementi può essere previsto in una certa misura in anticipo
  • Elaborazioni in cui l’aggiunta/rimozione di elementi è minima, concentrandosi sulla lettura
    List<String> list = new ArrayList<>();
    

Caratteristiche e casi d’uso adatti di LinkedList

LinkedList è implementata con una struttura a lista doppiamente collegata.

Caratteristiche principali:

  • Veloce per aggiungere e rimuovere elementi (soprattutto all’inizio o alla fine)
  • L’accesso casuale (get(index)) è lento (O(n))
  • Il consumo di memoria è leggermente superiore a quello di ArrayList

Situazioni adatte:

  • Situazioni in cui gli elementi vengono inseriti o rimossi frequentemente (soprattutto all’inizio o al centro)
  • Quando vuoi usarla come una Coda o uno Stack
  • Quando ci si concentra sull’iterazione e l’accesso per indice non è necessario
    List<String> list = new LinkedList<>();
    

Confronto delle prestazioni

La tabella seguente mostra la complessità temporale teorica (notazione Big O) per le operazioni più comuni.

OperationArrayListLinkedList
get(int index)O(1)O(n)
add(E e) (at the end)O(1)O(1)
add(int index, E e)O(n)O(n)
remove(int index)O(n)O(n)
IterationO(n)O(n)

* Il tempo di elaborazione reale può essere influenzato anche dalla dimensione dei dati, dall’ottimizzazione della JVM, ecc.

Punti per differenziare l’uso pratico

  • Se tratti i dati come una lista e accedi per indice, usa ArrayList
  • Se l’inserimento/rimozione all’inizio o al centro è frequente, usa LinkedList
  • Per elaborazioni sensibili alle prestazioni, esegui sempre benchmark e verifica

6. Uso avanzato delle List

Qui introdurremo tecniche avanzate per utilizzare le List di Java in modo ancora più comodo. Le List possono eseguire varie operazioni non solo come semplice raccolta di dati, ma anche tramite ordinamento, mescolamento, filtraggio, trasformazione, ecc.

Ordinare una List (Collections.sort)

Usando Collections.sort(), puoi ordinare gli elementi di una List in ordine crescente. Gli elementi devono implementare l’interfaccia Comparable.

import java.util.*;

List<String> fruits = new ArrayList<>();
fruits.add("banana");
fruits.add("apple");
fruits.add("orange");

Collections.sort(fruits);

System.out.println(fruits); // [apple, banana, orange]

Ordinamento in ordine personalizzato (usando Comparator)

fruits.sort(Comparator.reverseOrder()); // Sorts in descending order

Mescolare una List (Collections.shuffle)

Per riordinare casualmente gli elementi, puoi usare Collections.shuffle().

Collections.shuffle(fruits);
System.out.println(fruits); // [banana, orange, apple] (example)

Questo è utile quando vuoi un mazzo di carte per un gioco o un ordine di visualizzazione casuale.

Filtrare usando Stream API (filter)

Usando Stream a partire da Java 8, puoi scrivere codice conciso per estrarre solo gli elementi che soddisfano una condizione.

List<String> filtered = fruits.stream()
    .filter(fruit -> fruit.contains("a"))
    .collect(Collectors.toList());

System.out.println(filtered); // [apple, banana, orange] (depending on original content and filter)

Trasformazione usando Stream API (map)

Per trasformare gli elementi in un formato diverso, usa map().

List<Integer> lengths = fruits.stream()
    .map(String::length)
    .collect(Collectors.toList());

System.out.println(lengths); // Lengths of each fruit name [5, 6, 6] etc.

map() è uno strumento potente per la conversione di formato dei dati e il pre‑processing.

Riepilogo delle operazioni avanzate

OperationUsage ExampleMain Use Cases
SortCollections.sort(list)Sort in ascending order
ShuffleCollections.shuffle(list)Randomize the order of elements
Filterstream().filter(...).collect()Extract only elements that match a condition
Transformstream().map(...).collect()Transform the type or value of elements

7. Errori comuni e le loro soluzioni

Quando si lavora con le List in Java, una delle cose su cui i principianti inciampano spesso sono le “eccezioni (errori)”. Qui spiegheremo specificamente gli errori più rappresentativi che si verificano frequentemente, le loro cause e come risolverli.

IndexOutOfBoundsException

Causa:

Si verifica quando si tenta di accedere a un indice inesistente.

List<String> list = new ArrayList<>();
list.add("apple");

System.out.println(list.get(1)); // Error: Index 1 out of bounds

Soluzione:

Verifica la dimensione prima di accedere o controlla l’accesso con un ramo condizionale per garantire che l’indice sia valido.

if (list.size() > 1) {
    System.out.println(list.get(1));
}

NullPointerException

Causa:

Si verifica quando si chiama un metodo su una List o su un elemento della List che è null.

List<String> list = null;
list.add("apple"); // NullPointerException occurs

Soluzione:

Verifica in anticipo che la variabile non sia null, oppure utilizza Optional, ecc.

if (list != null) {
    list.add("apple");
}

Inoltre, fai attenzione a non dimenticare di inizializzare:

List<String> list = new ArrayList<>(); // Correct initialization

ConcurrentModificationException

Causa:

Si verifica quando la List viene modificata direttamente durante l’iterazione con un ciclo for-each o un Iterator.

for (String fruit : list) {
    if (fruit.equals("banana")) {
        list.remove(fruit); // ConcurrentModificationException
    }
}

Soluzione:

Usa un Iterator per rimuovere gli elementi in modo sicuro, oppure utilizza metodi come removeIf().

Iterator<String> it = list.iterator();
while (it.hasNext()) {
    if (it.next().equals("banana")) {
        it.remove(); // Safe removal
    }
}

Oppure, in modo più conciso a partire da Java 8:

list.removeIf(fruit -> fruit.equals("banana"));

Altri punti da notare

  • Verificare che la List non sia null
  • È molto comune dichiarare una variabile ma non usarla. L’inizializzazione è essenziale.
  • Comprendere che gli indici partono da 0
  • I principianti spesso pensano erroneamente che “il primo elemento abbia indice 1”.

Riepilogo delle contromisure per gli errori

Error NamePrimary CauseExample Solutions
IndexOutOfBoundsExceptionAccessing a non-existent indexCheck length with size()
NullPointerExceptionList or element is nullDon’t forget initialization, perform null checks
ConcurrentModificationExceptionDirectly modifying the List during iterationOperate with Iterator or utilize removeIf()

8. Conclusione

Rivedere le basi di Java List

In questo articolo, abbiamo spiegato passo passo le basi fino agli aspetti avanzati di List in Java. List è particolarmente utilizzata tra le collezioni Java ed è uno strumento importante per gestire i dati in modo flessibile.
Innanzitutto, dopo aver compreso cos’è una List, abbiamo appreso i seguenti punti:

  • La List è una collezione ordinata che consente duplicati e supporta le operazioni di indice
  • Esistono classi di implementazione rappresentative come ArrayList e LinkedList, ognuna con caratteristiche e casi d’uso diversi
  • Padroneggiare le operazioni di base (add, get, update, remove, search) consente una manipolazione flessibile dei dati
  • Elaborazione iterativa adatta alla situazione, come i cicli for, i for-each potenziati e lo Stream API
  • Supporta operazioni avanzate come ordinamento, filtraggio e trasformazione
  • Comprendere gli errori comuni, le loro cause e le soluzioni aiuta a prevenire i problemi

Differenziare l’uso di ArrayList e LinkedList

Scegliere quale implementazione di List utilizzare è importante e dovrebbe basarsi sul contenuto dell’elaborazione e sulla quantità di dati. I seguenti criteri possono servire da guida:

  • ArrayList: Accesso casuale frequente, principalmente lettura
  • LinkedList: Inserimento/cancellazione frequenti, l’ordine di accesso è importante

Verso l’apprendimento futuro

List è solo il “punto di ingresso” alle collezioni Java. Per gestire strutture dati e utility più avanzate, è consigliato approfondire la comprensione delle seguenti classi e funzionalità:

  • Set e Map: Gestione di elementi unici, struttura chiave‑valore
  • Classe utility Collections: Ordinamento, ricerca di min/max, ecc.
  • Utilizzare lo Stream API: Introduzione alla programmazione funzionale
  • Comprendere i Generics: Operazioni di collezione tipizzate in modo sicuro

Padroneggiare le basi di List renderà la tua programmazione Java complessiva significativamente più gestibile.

Domande frequenti (FAQ)

Abbiamo compilato i punti su cui i principianti hanno spesso domande riguardo alla List di Java. Abbiamo selezionato contenuti che si incontrano frequentemente nella pratica.

Q1. Qual è la differenza tra List di Java e Array?

A. Un array ha un numero fisso di elementi e la sua dimensione deve essere determinata al momento della dichiarazione. D’altra parte, una List ha una dimensione variabile, consentendo aggiunte e rimozioni flessibili di elementi. Inoltre, List offre molti metodi comodi (add, remove, contains, ecc.) ed è superiore in termini di leggibilità e manutenibilità.

Q2. Quale dovrei usare, ArrayList o LinkedList?

A. ArrayList è adatto principalmente quando c’è un frequente accesso casuale (recupero per indice). LinkedList è adatto quando l’inserimento e la rimozione di elementi avvengono frequentemente. In caso di dubbio, iniziare con ArrayList è generalmente consigliato.

Q3. Posso memorizzare tipi primitivi (come int o double) in una List?

A. Non direttamente. Poiché la List di Java gestisce solo tipi oggetto, per i tipi primitivi come int è necessario usare le loro classi wrapper corrispondenti (Integer, Double, ecc.).

List<Integer> numbers = new ArrayList<>();
numbers.add(10); // Auto-boxed and stored as Integer type

Q4. Come posso ordinare gli elementi in una List?

A. Puoi ordinare in ordine crescente usando Collections.sort(list). Inoltre, se vuoi ordinare in un ordine personalizzato, puoi specificare un Comparator per un ordinamento flessibile.

Q5. Cosa devo fare se voglio gestire gli elementi senza duplicati?

A. La List è una collezione che permette duplicati. Se vuoi evitare i duplicati, considera l’uso di un Set (ad esempio HashSet). Tuttavia, nota che l’ordine non è garantito. Se vuoi rimuovere i duplicati mantenendo la struttura come List, è possibile anche il seguente processamento con Stream:

List<String> distinctList = list.stream()
    .distinct()
    .collect(Collectors.toList());

Q6. Cosa devo fare quando voglio svuotare tutti gli elementi da una List?

A. Puoi rimuovere tutti gli elementi da una List usando il metodo clear().

list.clear();

Q7. Quali sono le operazioni più frequentemente usate in una List?

A. Le operazioni più frequentemente usate in pratica sono add (aggiunta), get (recupero), remove (rimozione) e size (ottenere la dimensione). Padroneggiare queste coprirà la maggior parte dell’elaborazione di base.