1. Introduzione
In passato abbiamo già avuto a che fare con gli «array “infiniti”» — le liste. Approfondiamo le nostre conoscenze e, per farlo, chiediamoci ancora una volta che cos’è un array «classico». Se ci pensate, ricorda una cassetta degli attrezzi con un numero fisso di scomparti. Supponiamo che nella cassetta ci siano 10 celle. Vi compare un undicesimo attrezzo: e adesso? Bisogna comprare una nuova cassetta! Allo stesso modo, un array tradizionale ha una dimensione fissa e, dopo la creazione, la sua lunghezza non cambia.
Se serve aggiungere o rimuovere un elemento, occorre creare un nuovo array e copiare i dati manualmente. In un array è facile e veloce trovare un elemento per indice, ma inserire un elemento nel mezzo dell’array non significa semplicemente «inserire», bensì «spostare tutto a destra», e in caso di rimozione — «spostare tutto a sinistra». È lento e scomodo. Inoltre, l’array non contiene alcuna «logica» aggiuntiva: mantiene solo un insieme di celle, mentre ordinamento, ricerca per contenuto o verifica dell’unicità vanno fatti con strumenti esterni.
Esempio: elenco dinamico di studenti
Supponiamo che stiate scrivendo un’applicazione per la gestione degli studenti in un gruppo. All’inizio nel gruppo ci sono 5 persone, poi ne arriva un’altra, poi qualcuno se ne va. Con un array sarebbe così:
String[] students = new String[5];
students[0] = "Ivan";
students[1] = "Mariya";
// e così via...
// Ops, è arrivato un altro studente
// Bisogna creare un nuovo array!
String[] newStudents = new String[6];
for (int i = 0; i < students.length; i++) {
newStudents[i] = students[i];
}
newStudents[5] = "Aleksey";
students = newStudents;
Comodo? Diciamo di no. E se di operazioni del genere ce ne sono molte? A quel punto si desidera qualcosa di più comodo...
2. Che cos’è una collezione?
Una collezione è un oggetto che funge da contenitore per memorizzare un gruppo di altri oggetti (elementi). Le collezioni consentono di aggiungere, rimuovere, iterare gli elementi e anche di eseguire altre operazioni: ricerca, ordinamento, filtraggio, ecc.
In Java tutte le collezioni implementano o ereditano dall’interfaccia Collection (oppure, per le mappe — da Map). Una collezione non è solo «un mucchio di cose», ma una struttura che fornisce un insieme di metodi comodo e ben progettato per lavorare con gli elementi.
Perché le collezioni sono oggetti?
Perché le collezioni sono implementate come classi; ciò significa che potete creare collezioni di qualsiasi oggetto, combinarle, ereditarle, estenderle, usarle nelle vostre classi e metodi.
Esempio:
import java.util.ArrayList;
import java.util.List;
List<String> students = new ArrayList<>();
students.add("Ivan");
students.add("Mariya");
students.add("Aleksey");
Voilà! Ora potete aggiungere quanti studenti volete senza preoccuparvi della dimensione dell’array.
3. Problemi tipici che le collezioni risolvono
Le collezioni sono un coltellino svizzero per lavorare con i dati. Ecco che cosa permettono di fare:
- Memorizzazione di elenchi dinamici di dati: ad esempio, l’elenco degli studenti, le attività in un planner, i messaggi in chat.
- Ricerca e filtraggio: trovare rapidamente un elemento, verificarne la presenza, ottenere tutti gli elementi che soddisfano una certa condizione.
- Ordinamento: ordinare facilmente gli elementi in base al criterio desiderato.
- Aggiunta e rimozione di elementi: inserire e rimuovere elementi in qualsiasi punto della collezione senza dover copiare manualmente gli array.
- Raggruppamento per chiave: per esempio, una rubrica in cui a ogni nome corrisponde un numero di telefono.
- Garanzia di unicità: ad esempio, l’insieme di tutte le parole uniche in un testo.
Esempio: rubrica telefonica
Con un array:
- Come trovare il numero a partire dal nome? Bisogna scorrere l’array e confrontare i nomi.
- Come aggiungere una nuova coppia? Bisogna ridimensionare l’array.
- Come garantire che i nomi non si ripetano? Ancora più complicato.
Con una collezione:
- Usiamo Map<String, String> — e tutto funziona «out of the box».
4. Panoramica dei principali tipi di collezioni
In Java le collezioni si dividono in tre gruppi principali:
| Tipo di collezione | Interfaccia/Classe | A cosa serve |
|---|---|---|
| Lista | List, ArrayList | Insieme ordinato di elementi, consente duplicati, accesso per indice |
| Insieme (Set) | Set, HashSet | Contiene solo elementi unici, l’ordine non è garantito |
| Mappa | Map, HashMap | Contiene coppie chiave–valore, ricerca rapida per chiave |
Liste (List)
- Collezioni ordinate che consentono duplicati.
- Si può ottenere un elemento per indice.
- Esempi: ArrayList, LinkedList.
Insiemi (Set)
- Contengono solo elementi unici.
- Non c’è accesso per indice.
- Esempi: HashSet, TreeSet.
Mappe (Map)
- Contengono coppie chiave–valore.
- Ricerca rapida per chiave.
- Esempi: HashMap, TreeMap.
Schema visivo (molto approssimativo):
+------------------+ +-------------------+ +---------------------+
| List | | Set | | Map |
|------------------| |-------------------| |---------------------|
| [a, b, c, d, a] | | {a, b, c, d} | | {a=1, b=2, c=3} |
| Indicizzazione: sì | | Indicizzazione: no | | Ricerca per chiave |
| Duplicati: sì | | Duplicati: no | | Chiavi uniche |
+------------------+ +-------------------+ +---------------------+
5. Dettagli utili
Quando usare quale collezione?
List — quando l’ordine degli elementi è importante, servono duplicati e serve l’accesso per indice (ad esempio, un elenco di attività, la cronologia dei messaggi).
Set — quando servono solo elementi unici e l’ordine non è importante (ad esempio, l’insieme degli utenti unici).
Map — quando bisogna associare chiavi e valori (ad esempio, una rubrica dove il nome è la chiave e il telefono è il valore).
Analogie dalla vita quotidiana
List — una fila in mensa: chi arriva prima viene servito per primo; ci si può mettere in fila più volte (duplicati).
Set — la lista degli invitati a una festa: ogni ospite compare una sola volta (unicità).
Map — una rubrica: a ogni nome è associato un numero di telefono.
Promemoria rapido: collezioni vs array
| Array (int[]) | Collezione (List<Integer>) | |
|---|---|---|
| Dimensione | Fissa | Dinamica |
| Aggiunta di un elemento | Scomoda | Facile: add() |
| Rimozione di un elemento | Scomoda | Facile: remove() |
| Ricerca per valore | Scansione manuale | Metodi: contains(), ecc. |
| Ordinamento | Con Arrays.sort() | Con Collections.sort(), metodi delle collezioni |
| Supporto dell’unicità | No | Con Set |
| Coppie chiave–valore | No | Con Map |
6. Relazione tra collezioni e OOP
Le collezioni sono oggetti che implementano specifiche interfacce (List, Set, Map). Questo significa che potete:
- Memorizzare in collezioni qualsiasi oggetto, compresi istanze delle vostre classi.
- Creare collezioni di collezioni (ad esempio, una lista di liste).
- Usare le collezioni come parametri e valori di ritorno dei metodi.
- Estendere la funzionalità delle collezioni tramite ereditarietà e composizione.
Esempio: collezione di oggetti della vostra classe
import java.util.ArrayList;
import java.util.List;
class Student {
String name;
int age;
// Costruttore, getter/setter, ecc.
}
public class Main {
public static void main(String[] args) {
List<Student> group = new ArrayList<>();
group.add(new Student("Ivan", 20));
group.add(new Student("Mariya", 21));
// e così via...
}
}
7. Errori tipici nell’uso delle collezioni
Errore n. 1: Uso di collezioni senza tipo (raw types).
Se scrivete ArrayList list = new ArrayList(), allora quando aggiungete qualsiasi oggetto (ad esempio stringhe e numeri mescolati) il compilatore non segnalerà errori, ma poi, tentando di estrarre un elemento e convertirlo nel tipo desiderato, potete ottenere un errore a runtime (ClassCastException). Usate sempre i generics: ArrayList<String> list = new ArrayList<>().
Errore n. 2: Avete dimenticato di importare la classe necessaria.
Se vedete l’errore «cannot find symbol», verificate che all’inizio del file ci sia la riga import java.util.ArrayList; o l’import corretto per la vostra collezione.
Errore n. 3: Confusione tra collezioni e array.
Una collezione non è un array! Una collezione non ha il campo length: usate invece il metodo size(). Un array non ha il metodo add(), e una collezione non ha l’operatore [] per l’accesso per indice (solo le liste tramite get(index)).
Errore n. 4: Aspettarsi che l’ordine degli elementi sia sempre preservato.
Se usate Set o Map, l’ordine degli elementi non è garantito (a meno che non si usino implementazioni speciali come LinkedHashSet o TreeMap). Per dati ordinati, usate List o le collezioni appropriate.
Errore n. 5: Uso di tipi primitivi nelle collezioni.
Le collezioni possono contenere solo oggetti, non tipi primitivi. Non si può quindi creare List<int>, ma solo List<Integer>. Non dimenticate le classi wrapper!
GO TO FULL VERSION