Was sind Sammlungen?
Sammlungen in Java sind ein Framework (eine Sammlung von Klassen und Schnittstellen), das die Arbeit mit Gruppen von Objekten vereinfacht: deren Speicherung, Suche, Sortierung, Löschen usw.
Anstatt Arrays und Methoden zum Hinzufügen/Entfernen von Elementen selbst zu schreiben, bietet Java vorgefertigte Datenstrukturen.
Sammlungen befinden sich im Paket java.util und sind im Java Collections Framework (JCF) zusammengefasst.
Wo werden sie verwendet?
- Speicherung von Daten (z.B. Liste von Benutzern oder Bestellungen in einem Online-Shop);
- Suche und Filterung (z.B. alle Bestellungen über 100 €);
- Sortierung (nach Datum, Alphabet usw.);
- Arbeit mit eindeutigen Daten (z.B. Liste von Login-Namen ohne Duplikate);
- Schlüssel-Wert-Zuordnung (Anwendungskonfiguration oder Cache).
Warum ist es wichtig, das zu wissen?
- 90% der Aufgaben in der Entwicklung beziehen sich auf die Speicherung und Verarbeitung von Daten.
- Sammlungen sparen Zeit – sie sind bereits optimiert und getestet.
- Viele Frameworks (Spring, Hibernate) verwenden Sammlungen intern.
Hauptschnittstellen von Sammlungen
Alles dreht sich um Collection und Map.
1) Schnittstelle Collection
Unterteilt in:
- List – geordnete Listen, erlauben Duplikate.
- Implementierungen:
ArrayList,LinkedList,Vector,Stack.
- Implementierungen:
- Set – Mengen, eindeutige Elemente.
- Implementierungen:
HashSet,LinkedHashSet,TreeSet.
- Implementierungen:
- Queue/Deque – Warteschlangen (FIFO, LIFO).
- Implementierungen:
PriorityQueue,ArrayDeque.
- Implementierungen:
2) Schnittstelle Map
Speichert Schlüssel-Wert-Paare.
- Implementierungen:
HashMap,LinkedHashMap,TreeMap,Hashtable,ConcurrentHashMap.
Hierarchie des Java Collections Frameworks
Iterable
│
Collection
┌────────────┼────────────────┐
│ │ │
List Set Queue/Deque
│ │ │
┌───┴─────┐ ┌───┴─────────┐ ┌───┴─────────┐
ArrayList HashSet PriorityQueue
LinkedList LinkedHashSet ArrayDeque
Vector TreeSet
Stack
Map (Does not inherit from Collection)
┌─────────────┬─────────────────┐
HashMap LinkedHashMap TreeMap
Hashtable ConcurrentHashMapUnterschiede bei den Collections
ArrayList— schneller Zugriff über den Index, langsames Löschen in der Mitte.LinkedList— langsamer Zugriff über den Index, schnelles Einfügen/Löschen.HashSet— eindeutige Elemente, Reihenfolge nicht garantiertLinkedHashSet— behält die Einfügereihenfolge bei.TreeSet— speichert Elemente in sortierter Reihenfolge.HashMap— Schlüssel-Wert-Paare, Reihenfolge nicht garantiert.LinkedHashMap— behält die Einfügereihenfolge bei.TreeMap— Schlüssel werden automatisch sortiert.
Beziehung zu anderen Konzepten
- Generics: Collections verwenden fast immer Generics (z. B.
List<String>). - Stream API: Collections werden oft in Streams umgewandelt, um eine bequemere Verarbeitung zu ermöglichen (
list.stream().filter(...).map(...).collect(...)). - Multithreading: Es gibt nebenläufige Implementierungen (
ConcurrentHashMap,CopyOnWriteArrayList).
Codebeispiel
Wir betrachten:
List→ArrayList,LinkedListSet→HashSet,TreeSetMap→HashMap,TreeMap
und verstehen ihre Unterschiede in der Praxis.
import java.util.*;
public class CollectionsDemo {
public static void main(String[] args) {
// ====== LIST ======
List<String> arrayList = new ArrayList<>();
arrayList.add("Java");
arrayList.add("Python");
arrayList.add("C++");
arrayList.add("Java"); // allows duplicates
System.out.println("ArrayList: " + arrayList);
List<String> linkedList = new LinkedList<>();
linkedList.add("First");
linkedList.add("Second");
linkedList.add("Third");
System.out.println("LinkedList: " + linkedList);
// ====== SET ======
Set<String> hashSet = new HashSet<>();
hashSet.add("One");
hashSet.add("Two");
hashSet.add("Three");
hashSet.add("Two"); // duplicate is ignored
System.out.println("HashSet: " + hashSet);
Set<String> treeSet = new TreeSet<>();
treeSet.add("Banana");
treeSet.add("Apple");
treeSet.add("Orange");
System.out.println("TreeSet (sorted): " + treeSet);
// ====== MAP ======
Map<Integer, String> hashMap = new HashMap<>();
hashMap.put(1, "One");
hashMap.put(2, "Two");
hashMap.put(3, "Three");
hashMap.put(2, "NewTwo"); // overwrites the value for key 2
System.out.println("HashMap: " + hashMap);
Map<Integer, String> treeMap = new TreeMap<>();
treeMap.put(30, "Thirty");
treeMap.put(10, "Ten");
treeMap.put(20, "Twenty");
System.out.println("TreeMap (sorted by key): " + treeMap);
}
}ArrayList— behält die Reihenfolge bei, erlaubt Duplikate. Ausgabe:[Java, Python, C++, Java].LinkedList— ebenfalls eine Liste, aber für Einfügungen/Löschungen optimiert.HashSet— speichert nur eindeutige Elemente, Reihenfolge ist unvorhersehbar.TreeSet— eindeutig + sortiert.HashMap— Schlüssel sind eindeutig, Werte können überschrieben werden.TreeMap— Schlüssel werden automatisch sortiert.
Häufige Fehler
- Generics vergessen:
List list = new ArrayList(); // raw type, badBesser so:
List<String> list = new ArrayList<>();- Falsche Collection verwendet:
ArrayListstattHashSet, wenn eindeutige Werte benötigt werden.LinkedListstattArrayList, wenn viele Zugriffe über den Index erfolgen.
- Vergleich mit
==stattequals()für Objekte in Collections.
Best Practices
- Über das Interface deklarieren (
List,Set,Map), nicht über die konkrete Klasse:
List<String> list = new ArrayList<>();- Collection je nach Aufgabe wählen:
- schneller Zugriff über Index →
ArrayList - eindeutige Elemente →
HashSet - Sortierung →
TreeSet/TreeMap - Schlüssel-Wert-Paare →
HashMap
- schneller Zugriff über Index →
Collections Spickzettel
List (geordnete Listen, die Duplikate erlauben)
| Klasse | Merkmale | Wann verwenden |
|---|---|---|
| ArrayList | Schneller Indexzugriff O(1), langsames Einfügen/Löschen in der Mitte | Wenn viele Lesevorgänge und wenige Updates |
| LinkedList | Schnelles Einfügen/Löschen O(1) am Anfang/in der Mitte, langsamer Indexzugriff | Wenn häufig Einfügungen/Löschungen erfolgen |
| Vector / Stack | Alte synchronisierte Implementierungen | Selten verwendet, besser ArrayDeque nutzen |
Set (sets, only unique elements)
| Klasse | Merkmale | Wann verwenden |
|---|---|---|
| HashSet | Keine Reihenfolge, eindeutige Elemente, schneller Zugriff O(1) | Wenn nur eindeutige Werte benötigt werden |
| LinkedHashSet | Behält die Einfügereihenfolge bei | Wenn eindeutige Werte mit Reihenfolge benötigt |
| TreeSet | Automatisch sortiert | Wenn eindeutige Werte mit Sortierung benötigt |
Map (key–value)
| Klasse | Merkmale | Wann verwenden |
|---|---|---|
| HashMap | Schneller Zugriff O(1), Reihenfolge nicht garantiert | Am häufigsten (Cache, Einstellungen usw.) |
| LinkedHashMap | Behält die Einfügereihenfolge bei | Wenn die Reihenfolge der Schlüssel wichtig ist |
| TreeMap | Automatisch nach Schlüssel sortiert | Wenn eine sortierte Map benötigt wird |
| ConcurrentHashMap | Thread-sicher, nicht blockierend | Für Multithreading-Umgebungen |
Queue / Deque (queues and stacks)
| Klasse | Merkmale | Wann verwenden |
|---|---|---|
| ArrayDeque | Schneller als Stack und LinkedList | Für Stack (LIFO) oder Queue (FIFO) |
| PriorityQueue | Elemente nach Priorität sortiert | Für prioritätsbasierte Warteschlangen |
Tipps
- Über das Interface deklarieren:
List<String> list = new ArrayList<>();- Für Multithreading
Concurrent-Versionen verwenden (ConcurrentHashMap,CopyOnWriteArrayList). - Für große Datenmengen und Filterungen ist der Stream API besonders praktisch.