W3docs

Java Collection Interface

Das root Collection Interface in Java und der Vertrag, den jede List, Set und Queue davon erbt.

java.util.Collection<E> ist die Wurzel des Teils des Frameworks, der einzelne Elemente enthält — jede List, Set, Queue und Deque implementiert es (die einzige Familie, die dies nicht tut, ist Map, deren Elemente Einträge und keine einzelnen Werte sind). Alles, was man "unabhängig von der Gruppe" tun kann — hinzufügen, entfernen, contains abfragen, iterieren, zählen, in ein Array umwandeln, streamen — ist hier deklariert. Dieses Kapitel beschreibt den Vertrag: die Methoden, auf die man sich bei jeder Collection verlassen kann, die wenigen, die eine Ausnahme werfen können, und das Iterationsmodell, das jede Implementierung erbt.

Die Hierarchie auf einen Blick

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 queue

Collection erweitert Iterable<E>, weshalb jede Collection mit der for-each-Schleife funktioniert. Die beiden Spezialisierungen von CollectionSet und Queue — verfeinern den Vertrag; Map hat eine eigene Wurzel.

Kernmethoden jeder Collection

Unten ist die vollständige Menge der Instanzmethoden auf Collection, nach Zweck gruppiert. Merken Sie sich eher die Kategorien als die Liste — sobald Sie wissen, dass es eine Methode namens removeIf gibt, können Sie sie finden.

Größe und Leerheit

  • int size() — Elementanzahl.
  • boolean isEmpty()size() == 0, aber oft schneller.

Hinzufügen

  • boolean add(E e) — fügt ein Element hinzu. Gibt true zurück, wenn sich die Collection geändert hat. (Ein Set gibt false für ein Duplikat zurück.)
  • boolean addAll(Collection<? extends E> c) — fügt jedes Element von c hinzu.

Entfernen

  • boolean remove(Object o) — entfernt ein Vorkommen von o.
  • boolean removeAll(Collection<?> c) — entfernt jedes Element, das in c vorkommt.
  • boolean retainAll(Collection<?> c) — behält nur die Elemente in c (Schnittmenge).
  • boolean removeIf(Predicate<? super E> filter) — entfernt jedes Element, das dem Prädikat entspricht. Die sauberste Methode zum In-Place-Filtern.
  • void clear() — leert die Collection.

Abfragen

  • boolean contains(Object o) — Mitgliedschaftstest.
  • boolean containsAll(Collection<?> c) — Teilmengentest.

Iteration und Massenansichten

  • Iterator<E> iterator() — der zugrunde liegende Iterator; was for-each verwendet.
  • Stream<E> stream() / parallelStream() — öffnet einen Stream über die Elemente.
  • void forEach(Consumer<? super E> action) — von Iterable geerbt. Die funktionale Iterationsform.

Array-Konvertierung

  • Object[] toArray()
  • <T> T[] toArray(T[] a) und das neuere <T> T[] toArray(IntFunction<T[]> generator) (Java 11+) — typisiertes Array.

Das ist das gesamte Interface. Jede Liste, jedes Set und jede Queue, der Sie in diesem Teil begegnen werden, ist nur eine andere Implementierung dieser Methoden plus einige eigene.

Gleichheit und equals / hashCode

Collection.equals(Object) ist nicht auf der Wurzel definiert — jedes Sub-Interface legt fest, was Gleichheit für es bedeutet. List erfordert gleiche Elemente in gleicher Reihenfolge; Set erfordert gleiche Elemente unabhängig von der Reihenfolge; Queue definiert equals überhaupt nicht (eine LinkedList-Queue und eine ArrayDeque-Queue mit demselben Inhalt sind nicht gleich, da der Vergleich auf Identität zurückfällt). Vergleichen Sie keine Collections über Familien hinweg und erwarten Sie Symmetrie.

Elemente, die in einer Collection gespeichert sind, müssen ein vernünftiges equals / hashCode haben, wenn contains, remove und (bei hash-basierten Collections) Lookups korrekt funktionieren sollen. Den Vertrag haben wir im Kapitel equals und hashCode behandelt — das ist die Voraussetzung für die Verwendung von Set und Map mit eigenen Klassen.

Optionale Operationen

Einige Collections sind unveränderlich — List.of(1,2,3), Collections.unmodifiableList(list), die von Map.keySet() bei bestimmten Implementierungen zurückgegebenen Views usw. Sie implementieren weiterhin Collection, aber das Aufrufen von add, remove, clear oder einer anderen mutierenden Methode wirft UnsupportedOperationException. Das Javadoc nennt diese "optionale Operationen." Das ist das Nächste, was Java einem Laufzeit-Opt-out für Teile eines Interfaces hat; der Preis ist, dass der Compiler den Fehler nicht abfangen kann — man erfährt es beim ersten Werfen.

Eine sichere Regel: Wenn Sie die Collection nicht selbst erstellt haben, behandeln Sie sie als möglicherweise unveränderlich. Wenn Sie eine veränderliche Kopie benötigen, führen Sie zuerst new ArrayList<>(received) aus.

Iteration: drei Formen, ein zugrunde liegender Mechanismus

Jede Collection unterstützt drei Iterationsstile, und alle drei enden damit, iterator() aufzurufen:

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
}

Warum Formen 1 und 3 beide noch relevant sind: Die for-each-Schleife kann die zugrunde liegende Collection nicht modifizieren, ohne eine ConcurrentModificationException zu werfen. Wenn Sie während der Iteration entfernen müssen, greifen Sie auf den expliziten Iterator zurück. Das Kapitel Iterators später in diesem Teil behandelt das Protokoll im Detail.

Mengenalgebra mit Massenoperationen

Die Massenoperationen verwandeln eine Collection in einen Mengenalgebra-Rechner (unabhängig davon, ob es ein Set ist — sie funktionieren auch auf 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));     // difference

Dies ist die sichere, abhängigkeitsfreie Methode, um "nur die Elemente behalten, die auch in b sind" auszudrücken, ohne eine Schleife zu schreiben. Sie modifizieren den Empfänger — wenn Sie ein unveränderliches Ergebnis benötigen, kopieren Sie zuerst.

Ein ausgearbeitetes Beispiel: jede Methode nebeneinander

Das folgende Programm übt jede Kategorie der Collection-Methode gegen dieselbe ArrayList aus, damit Sie sie an einem Ort sehen und den Vertrag beobachten können.

java— editable, runs on the server

Zwei Dinge sind aus der Ausgabe hervorzuheben:

  1. remove("red") hat nur das erste Vorkommen entfernt — das ist der Vertrag bei Collection. Um jede Übereinstimmung zu entfernen, verwenden Sie removeIf (man sieht es danach, wo jedes Wort länger als vier Zeichen entfernt wird).
  2. Die UnsupportedOperationException von frozen.add("d") ist die "optionale Operationen"-Regel in Aktion. frozen implementiert Collection, sodass der Aufruf kompiliert. Die Implementierung hat sich entschieden, dies nicht zu unterstützen, und man erfährt es zur Laufzeit.

Was kommt als Nächstes

Collection ist der abstrakte Vertrag. Die erste konkrete Verfeinerung, der Sie begegnen werden, ist diejenige, die Reihenfolge und Indizierung hinzufügt — das List Interface. Dort kommen indizierter Zugriff, Teillisten und reihenfolgebewahrende Operationen ins Spiel.

Übungen

Übung
Sie haben eine `Collection<String>` und möchten jedes Element entfernen, dessen Länge größer als vier ist. Welcher Ansatz ist der idiomatische Einzeiler?
Sie haben eine `Collection<String>` und möchten jedes Element entfernen, dessen Länge größer als vier ist. Welcher Ansatz ist der idiomatische Einzeiler?
Was this page helpful?