SemaTrain Logo Ein Fachportal von SemaTrain

Collections & Generics

Sie lernen, List / Set / Map gezielt auszuwählen, APIs typsicher zu designen und Generics & Wildcards richtig einzusetzen – damit Code robust und wartbar bleibt.

Hinweis: Fokus ist Praxis & Design (API-Entscheidungen), nicht „jede Methode auswendig“.

Java Fortgeschrittenen Schulung – Kursbezug

Dieses Kapitel ist Teil des Lernpfads zur Java Fortgeschrittenen Schulung. Fokus: Collections-Entscheidungen + typsichere APIs mit Generics (SemaTrain-Kontext).

Ziel dieses Kapitels: Sie wählen List/Set/Map bewusst, reduzieren Bugs durch Typsicherheit und nutzen Wildcards (Producer/Consumer) für saubere API-Signaturen.

Worum geht’s?

Lehr-/Lernziele

Nach diesem Kapitel können Sie …

Welche Collection wofür?

Merksatz: List = Reihenfolge/Index, Set = eindeutig, Map = Schlüssel → Wert.

List / Set / Map: kurze Intuition (SemaTrain-Beispiel) (Java)
import java.util.*;

public class Auswahl {
  public static void main(String[] args) {
    List<String> teilnehmer = new ArrayList<>();       // Reihenfolge wichtig, Duplikate möglich
    Set<String> tags = new HashSet<>();                // eindeutig
    Map<String, Integer> plaetzeProOrt = new HashMap<>(); // Lookup per Schlüssel

    teilnehmer.add("Mia");
    teilnehmer.add("Mia"); // Duplikat ok
    tags.add("Java");
    tags.add("Java"); // Duplikat wird ignoriert

    plaetzeProOrt.put("Hamburg", 12);
    System.out.println(teilnehmer);
    System.out.println(tags);
    System.out.println(plaetzeProOrt.get("Hamburg"));
  }
}

Generics: Typsicherheit ohne Casting

Mit Generics vermeiden Sie ClassCastExceptions und machen Absichten im Code sichtbar.

Generics verhindern Mischtypen (Compile-Time Safety) (Java)
import java.util.*;

public class GenericsDemo {
  public static void main(String[] args) {

    List<Object> roh = new ArrayList<>();
    roh.add("Java");
    roh.add(123); // Mischtyp → später Ärger

    List<String> sicher = new ArrayList<>();
    sicher.add("Java");
    // sicher.add(123); // Compiler verhindert das
  }
}

Map-Pattern: Zählen in der Praxis

Beispiel: Buchungen pro Ort zählen (SemaTrain: „wie oft wurde eine Stadt gewählt?“).

Map zählen: merge(…, 1, Integer::sum) (Java)
import java.util.*;

public class Zaehlen {
  public static void main(String[] args) {
    List<String> buchungen = Arrays.asList("Hamburg","Berlin","Hamburg","Koeln","Berlin");

    Map<String, Integer> count = new HashMap<>();
    for(String ort : buchungen) {
      count.merge(ort, 1, Integer::sum);
    }

    System.out.println(count);
  }
}

Wildcards: ? extends / ? super (PECS)

PECS: Producer = extends (lesen), Consumer = super (schreiben).

Wildcards + PECS: lesen mit extends, schreiben mit super (Java)
import java.util.*;

public class Wildcards {

  // Producer: wir lesen Numbers
  static double summe(List<? extends Number> nums) {
    double s = 0;
    for (Number n : nums) s += n.doubleValue();
    return s;
  }

  // Consumer: wir schreiben Integers hinein
  static void fuegeDefaultsHinzu(List<? super Integer> out) {
    out.add(1);
    out.add(2);
  }

  public static void main(String[] args) {
    System.out.println(summe(Arrays.asList(1,2,3)));

    List<Number> ziel = new ArrayList<>();
    fuegeDefaultsHinzu(ziel);
    System.out.println(ziel);
  }
}

Praxisaufgabe (Mini)

Beitrag zu den Lehr-/Lernzielen: LZ1 (Collection-Wahl) · LZ2 (Generics) · LZ3 (Wildcards)

  1. Erstellen Sie eine List<String> mit 6 Buchungs-Orten (z.B. Hamburg, Berlin …) – gern mit Duplikaten.
  2. Erzeugen Sie daraus ein Set<String> (Duplikate entfernen).
  3. Bauen Sie eine Map<String,Integer>, die pro Ort die Anzahl Vorkommen zählt.
  4. Bonus: Implementieren Sie summe(List<? extends Number>) und summieren Sie 3 Beispiel-Umsätze.
Lösung anzeigen
Lösung: List → Set → Map + Wildcard-Methode (SemaTrain-Bezug) (Java)
import java.util.*;

public class Praxis {
  public static void main(String[] args) {

    List<String> orte = Arrays.asList(
      "Hamburg","Berlin","Hamburg","Muenchen","Koeln","Berlin"
    );

    // (LZ1) Set: Duplikate entfernen
    Set<String> eindeutig = new HashSet<>(orte);

    // (LZ1) Map: zählen
    Map<String, Integer> zaehlung = new HashMap<>();
    for(String ort : orte) zaehlung.merge(ort, 1, Integer::sum);

    System.out.println("Eindeutige Orte: " + eindeutig);
    System.out.println("Buchungen pro Ort: " + zaehlung);

    // (LZ3) Producer = extends
    System.out.println("Umsatz-Summe: " + summe(Arrays.asList(199.0, 299.0, 149.5)));
  }

  static double summe(List<? extends Number> nums) {
    double s = 0;
    for(Number n : nums) s += n.doubleValue();
    return s;
  }
}
Optional: typische Stolperfallen
  • Generics sind invariabel: List<Object> ist nicht List<String>.
  • ? extends: gut zum Lesen – aber i.d.R. nicht sinnvoll „hinzufügen“.
  • equals/hashCode: für Set/Map-Schlüssel müssen sie korrekt & stabil sein.

Kurz-Takeaways

Quiz: Collections & Generics (Lehr-/Lernziele Check)

1. (LZ1) Welche Collection ist am passendsten für „eindeutige Tags“?

2. (LZ2) Was ist ein Hauptvorteil von Generics?

3. (LZ3) Wofür steht PECS?

4. (LZ3) Welche Signatur ist korrekt, wenn eine Methode Numbers nur „lesen“ soll?

Praxisaufgabe

Mini-Projekt: „SemaTrain Booking-Stats“ (Collections + Generics im Kurskontext)

Beitrag zu den Lehr-/Lernzielen: LZ1 (Collection-Wahl) · LZ2 (Generics) · LZ3 (Wildcards)

Sie werten „Beispiel-Buchungen“ aus: Welche Orte werden häufig gewählt und wie kann man Umsätze typ-sicher summieren?

Lösung anzeigen
Lösung: SemaTrain Booking-Stats (List/Set/Map + Wildcards) (Java)
import java.util.*;

public class BookingStats {

  static Map<String,Integer> zaehleProOrt(List<String> orte) {
    Map<String,Integer> out = new HashMap<>();
    for(String ort : orte) out.merge(ort, 1, Integer::sum);
    return out;
  }

  static double summe(List<? extends Number> nums) {
    double s = 0;
    for(Number n : nums) s += n.doubleValue();
    return s;
  }

  public static void main(String[] args) {

    List<String> buchungen = Arrays.asList(
      "Hamburg","Berlin","Hamburg","Koeln","Berlin","Muenchen"
    );

    Set<String> eindeutig = new HashSet<>(buchungen);
    Map<String,Integer> stats = zaehleProOrt(buchungen);

    System.out.println("Eindeutige Orte: " + eindeutig);
    System.out.println("Buchungen pro Ort: " + stats);

    // Bonus: Beispiel-Umsätze (z.B. pro Buchung)
    System.out.println("Umsatz-Summe (Beispiel): " + summe(Arrays.asList(199.0, 299.0, 149.5)));
  }
}