Im Zuge der Überarbeitung der Collection-API in Java 1.2 gibt es eine Vielzahl unterschiedlicher Collections. Einen Überblick über die meist-genutzten Collections soll die unten stehende Abbildung verschaffen. Diese listet zu den verschiedenen Implementationen einige Eigenschaften auf, die die Collections voneinander unterscheiden.
Bei der ersten Eigenschaft „Typ“ wird ausgesagt welche Interfaces implementiert werden. Damit werden Aussagen darüber gemacht welche Zugriffsmöglichkeiten auf die Elemente möglich sind. Der Typ mit den wenigsten Möglichkeiten ist Set. Hier sind nur Basisoperationen wie add
, remove
und contains
vorhanden. Eine List bietet zudem noch die Möglichkeit, per Indizes Elemente hinzuzufügen, zu löschen oder auszulesen. Methoden wie push
und pop
, die Zugriff auf die Elemente in einer FIFO-Manier gewähren, sind für den Typ „Stack“ gegeben. Queues bieten die Methoden add/offer
, remove/poll
sowie element/peek
an, um auf die Elemente in Form einer Warteschlange zuzugreifen. Beim Typ Map handelt es sich eigentlich um keine echte Collection. Das Collection-Interface wird zwar tatsächlich nicht implementiert, dennoch werden auch Maps zum Speichern vieler Elemente, also als Collection, genutzt. Der größte Unterschied zu den restlichen Collections ist, dass aufgrund dieser Tatsache kein Iterator zum Durchlaufen der Elemente erzeugt werden kann. Der Zugriff wird stattdessen über die Methoden keySet
, values
und entrySet
(die drei sog. „Views“) realisiert.
Des weiteren fällt auf, dass viele der Collections nicht thread-safe sind. Dieses Problem lässt sich relativ einfach mit der Utility-Klasse Collections lösen. Diese bietet zum Beispiel für Maps die statische Methode
Map Collections.synchronizedMap(Map map)
an, die eine Map zurückliefert, die die selben Elemente enthält, deren Methoden aber
synchronized
sind. Bemerkenswert ist dabei auch, dass diese Methode auch für den Typ Map existiert, obwohl es sich bei dieser um keine Collection handelt.
Außerdem hat prinzipiell auch jede Klasse die Möglichkeit mit null
-Werten umgehen zu können. Hierfür muss lediglich bei der Erzeugung der Collection ein passender Comparator übergeben werden, der in der Lage ist, auch null
-Werte zu sortieren. Dieses Problem besteht nämlich ausschließlich bei den Implementierungen, die die Elemente mittels einem Comparator sortieren müssen.
Zu guter Letzt ist es wichtig zu wissen, dass die verschiedenen Implementierungen unterschiedlich schnell sind. Die Thread-sicheren Varianten sind normalerweise immer langsamer als ihre nicht-synchronisierten Alternativen. Aber auch mögliche Tuningparameter wie beispielsweise initial-capacity oder load-factor sollten sinnvollerweise an den konkreten Fall angepasst werden. Für welche Implementierung man sich letztlich entscheidet muss von der häufigsten Verwendungsart abhängig gemacht werden. Zum Beispiel ist eine ArrayList beim Zugriff auf ein indiziertes Element schneller als eine LinkedList. Die LinkedList ist dafür beim Einfügen neuer Elemente performanter. Da diese Implementierungsdetails allerdings über diesen Überblick hinausgehen, ist dafür im konkreten Anwendungsfall die offizielle API zu konsultieren.
Hier die Übersichtstabelle:
Typ | Duplikate erlaubt | Null erlaubt | Thread-Safe | Ordered | |
ArrayList | List | Ja | Ja | Nein | Insertion |
LinkedList | List, Stack, Queue | Ja | Ja | Nein | abhängig vom Typ |
Vector | List | Ja | Ja | Ja | Insertion |
Stack | Stack | Ja | Ja | Ja | LIFO |
HashSet | Set | Nein | Ja | Nein | Nein |
LinkedHashSet | Set | Nein | Ja | Nein | Insertion |
TreeSet | SortedSet | Nein | Nein | Nein | Keys |
HashMap | Map | Nur Values | Ja | Nein | Nein |
LinkedHashMap | Map | Nur Values | Ja | Nein | Insertion |
TreeMap | SortedMap | Nur Values | Nein | Nein | Keys |
Hashtable | Map | Nur Values | Nein | Ja | Nein |
Concurrent HashMap |
Map | Nur Values | Ja | Ja | Nein |
PriorityQueue | Queue | Ja | Nein | Nein | Via Comparator |
Priority BlockingQueue |
Queue | Ja | Nein | Ja | Via Comparator |
Concurrent LinkedQueue |
Queue | Ja | Ja | Ja | FIFO |