Interfaccia Collection in Java
L'interfaccia radice Collection in Java e il contratto ereditato da ogni lista, set e coda.
java.util.Collection<E> è la radice della parte del framework che contiene elementi singoli — ogni List, Set, Queue e Deque la implementa (l'unica famiglia che non lo fa è Map, i cui elementi sono entry, non valori singoli). Tutto ciò che puoi fare "indipendentemente dal gruppo" — aggiungere, rimuovere, verificare con contains, iterare, contare, convertire in array, usare stream — è dichiarato qui. Questo capitolo descrive il contratto: i metodi su cui puoi fare affidamento per qualsiasi collection, i pochi che possono lanciare eccezioni, e il modello di iterazione che ogni implementazione eredita.
La gerarchia in sintesi
Iterable<E>
└── Collection<E>
├── List<E> — ordered, indexed, duplicates allowed
├── Set<E> — no duplicates
│ └── SortedSet<E> → NavigableSet<E>
└── Queue<E> — "next in line"
└── Deque<E> — double-ended queueCollection estende Iterable<E>, motivo per cui ogni collection funziona con il ciclo for-each. Le due specializzazioni di Collection — Set e Queue — affinano il contratto; Map ha una propria radice.
Metodi principali presenti in ogni collection
Di seguito è riportato l'insieme completo dei metodi di istanza su Collection, raggruppati per scopo. Memorizza le categorie piuttosto che la lista — una volta che sai che esiste un metodo chiamato removeIf puoi trovarlo facilmente.
Dimensione e vuoto
int size()— conteggio degli elementi.boolean isEmpty()— equivalente asize() == 0ma spesso più veloce.
Aggiunta
boolean add(E e)— aggiunge un elemento. Restituiscetruese la collection è cambiata. (UnSetrestituiscefalseper un duplicato.)boolean addAll(Collection<? extends E> c)— aggiunge ogni elemento dic.
Rimozione
boolean remove(Object o)— rimuove una occorrenza dio.boolean removeAll(Collection<?> c)— rimuove ogni elemento che compare inc.boolean retainAll(Collection<?> c)— mantiene solo gli elementi inc(intersezione).boolean removeIf(Predicate<? super E> filter)— rimuove ogni elemento che soddisfa il predicato. Il modo più pulito per filtrare in place.void clear()— svuota la collection.
Interrogazione
boolean contains(Object o)— verifica l'appartenenza.boolean containsAll(Collection<?> c)— verifica il sottoinsieme.
Iterazione e viste bulk
Iterator<E> iterator()— l'iteratore sottostante; quello usato dalfor-each.Stream<E> stream()/parallelStream()— apre unStreamsugli elementi.void forEach(Consumer<? super E> action)— ereditato daIterable. La forma di iterazione funzionale.
Conversione in array
Object[] toArray()<T> T[] toArray(T[] a)e il più recente<T> T[] toArray(IntFunction<T[]> generator)(Java 11+) — array tipizzato.
Questa è l'intera interfaccia. Ogni lista, set e coda che incontrerai in questa parte è solo un'implementazione diversa di questi metodi più alcuni propri.
Uguaglianza ed equals / hashCode
Collection.equals(Object) non è definito sulla radice — ogni sotto-interfaccia specifica cosa significa uguaglianza per essa. List richiede stessi elementi nello stesso ordine; Set richiede stessi elementi indipendentemente dall'ordine; Queue non definisce equals (una LinkedList come coda e una ArrayDeque con lo stesso contenuto non sono uguali perché il confronto ricade sull'identità). Non confrontare collection tra famiglie diverse aspettandosi simmetria.
Gli elementi memorizzati in una Collection devono avere un equals / hashCode sensato se vuoi che contains, remove e (per le collection basate su hash) le ricerche funzionino correttamente. Abbiamo trattato il contratto nel capitolo equals e hashCode — questo è il prerequisito per usare Set e Map con le proprie classi.
Operazioni opzionali
Alcune collection sono non modificabili — List.of(1,2,3), Collections.unmodifiableList(list), le viste restituite da Map.keySet() su certe implementazioni, ecc. Implementano comunque Collection, ma chiamare add, remove, clear, o qualsiasi metodo mutante lancia UnsupportedOperationException. La Javadoc le chiama "operazioni opzionali." È il modo più vicino che Java ha a un opt-out a runtime per parti di un'interfaccia; il prezzo è che il compilatore non può rilevare l'errore — lo scopri al primo lancio.
Una regola sicura: se non hai costruito tu la collection, trattala come potenzialmente non modificabile. Se hai bisogno di una copia mutabile, fai prima new ArrayList<>(received).
Iterazione: tre forme, un meccanismo sottostante
Ogni collection supporta tre stili di iterazione, e tutti e tre finiscono per chiamare iterator():
Collection<String> names = List.of("Ada", "Linus", "Grace");
// 1. for-each — the everyday form
for (String n : names) System.out.println(n);
// 2. forEach with a lambda — declarative
names.forEach(System.out::println);
// 3. Iterator — when you need to remove during iteration
Iterator<String> it = names.iterator();
while (it.hasNext()) {
String s = it.next();
if (s.startsWith("L")) it.remove(); // safe; for-each can't do this
}Perché le forme 1 e 3 contano ancora entrambe: il ciclo for-each non può modificare la collection sottostante senza lanciare ConcurrentModificationException. Quando devi rimuovere durante l'iterazione, usi l'Iterator esplicito. Il capitolo sugli Iteratori più avanti in questa parte copre il protocollo in dettaglio.
Algebra degli insiemi con le operazioni bulk
Le operazioni bulk trasformano una collection in un calcolatore di algebra degli insiemi (indipendentemente dal fatto che sia un Set — funzionano anche su List):
Collection<Integer> a = new ArrayList<>(List.of(1, 2, 3, 4));
Collection<Integer> b = List.of(3, 4, 5);
a.addAll(b); // union (multiset)
a.retainAll(List.of(3, 4)); // intersection
a.removeAll(List.of(3)); // differenceQuesti sono il modo sicuro e senza dipendenze per esprimere "mantieni solo gli elementi presenti anche in b" senza scrivere un ciclo. Modificano il ricevitore — se hai bisogno di un risultato immutabile, copia prima.
Un esempio pratico: tutti i metodi, uno accanto all'altro
Il programma seguente esercita ogni categoria di metodo di Collection sullo stesso ArrayList, così puoi vederli in un unico posto e osservare il contratto in azione.
Due cose degne di nota dall'output:
remove("red")ha rimosso solo la prima occorrenza — questo è il contratto suCollection. Per rimuovere ogni corrispondenza, usaremoveIf(lo hai visto subito dopo, rimuovendo ogni parola più lunga di quattro caratteri).- L'
UnsupportedOperationExceptiondafrozen.add("d")è la regola delle "operazioni opzionali" in azione.frozenimplementaCollection, quindi la chiamata compila. L'implementazione ha scelto di non supportarla, e lo scopri a runtime.
Cosa viene dopo
Collection è il contratto astratto. Il primo perfezionamento concreto che incontrerai è quello che aggiunge ordine e indicizzazione — l'interfaccia List. Lì entrano in scena l'accesso indicizzato, i sotto-elenchi e le operazioni che preservano l'ordine.