RU | EN | DE

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?

  1. 90% der Aufgaben in der Entwicklung beziehen sich auf die Speicherung und Verarbeitung von Daten.
  2. Sammlungen sparen Zeit – sie sind bereits optimiert und getestet.
  3. 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.
  • Set – Mengen, eindeutige Elemente.
    • Implementierungen: HashSet, LinkedHashSet, TreeSet.
  • Queue/Deque – Warteschlangen (FIFO, LIFO).
    • Implementierungen: PriorityQueue, ArrayDeque.

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    ConcurrentHashMap

Unterschiede 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 garantiert
  • LinkedHashSet — 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:

  • ListArrayList, LinkedList
  • SetHashSet, TreeSet
  • MapHashMap, 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

  1. Generics vergessen:
List list = new ArrayList(); // raw type, bad

Besser so:

List<String> list = new ArrayList<>();
  1. Falsche Collection verwendet:
  • ArrayList statt HashSet, wenn eindeutige Werte benötigt werden.
  • LinkedList statt ArrayList, wenn viele Zugriffe über den Index erfolgen.
  1. Vergleich mit == statt equals() 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

Collections Spickzettel

List (geordnete Listen, die Duplikate erlauben)

KlasseMerkmaleWann verwenden
ArrayListSchneller Indexzugriff O(1), langsames Einfügen/Löschen in der MitteWenn viele Lesevorgänge und wenige Updates
LinkedListSchnelles Einfügen/Löschen O(1) am Anfang/in der Mitte, langsamer IndexzugriffWenn häufig Einfügungen/Löschungen erfolgen
Vector / StackAlte synchronisierte ImplementierungenSelten verwendet, besser ArrayDeque nutzen

Set (sets, only unique elements)

KlasseMerkmaleWann verwenden
HashSetKeine Reihenfolge, eindeutige Elemente, schneller Zugriff O(1)Wenn nur eindeutige Werte benötigt werden
LinkedHashSetBehält die Einfügereihenfolge beiWenn eindeutige Werte mit Reihenfolge benötigt
TreeSetAutomatisch sortiertWenn eindeutige Werte mit Sortierung benötigt

Map (key–value)

KlasseMerkmaleWann verwenden
HashMapSchneller Zugriff O(1), Reihenfolge nicht garantiertAm häufigsten (Cache, Einstellungen usw.)
LinkedHashMapBehält die Einfügereihenfolge beiWenn die Reihenfolge der Schlüssel wichtig ist
TreeMapAutomatisch nach Schlüssel sortiertWenn eine sortierte Map benötigt wird
ConcurrentHashMapThread-sicher, nicht blockierendFür Multithreading-Umgebungen

Queue / Deque (queues and stacks)

KlasseMerkmaleWann verwenden
ArrayDequeSchneller als Stack und LinkedListFür Stack (LIFO) oder Queue (FIFO)
PriorityQueueElemente nach Priorität sortiertFü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.