CodeGym /Kurse /JAVA 25 SELF /Operationen union, intersection, difference

Operationen union, intersection, difference

JAVA 25 SELF
Level 32 , Lektion 2
Verfügbar

1. Operation union (Mengenvereinigung)

In Java wird zur Darstellung von Mengen das Interface Set<T> verwendet. Im Gegensatz zu Listen (List) garantieren Mengen die Eindeutigkeit der Elemente und kümmern sich in der Regel nicht um die Reihenfolge (es sei denn, man verwendet spezielle Implementierungen wie LinkedHashSet). Die beliebtesten Implementierungen sind HashSet und TreeSet. Ihre Hauptaufgabe ist es, schnell festzustellen, ob ein Element vorhanden ist, und doppelte Einträge zu vermeiden.

Wann braucht man Mengen?

  • Wenn Einzigartigkeit wichtig ist: zum Beispiel die Liste aller eindeutigen Nutzer, die die Website besucht haben.
  • Wenn man schnell das Vorhandensein eines Elements prüfen möchte: die Methode contains bei HashSet arbeitet in der Regel in konstanter Zeit.
  • Wenn typische Operationen über Sammlungen benötigt werden: Vereinigung, Schnittmenge, Differenz.

Union ist die Vereinigung von zwei oder mehr Mengen: Das Ergebnis enthält alle Elemente aus beiden Ausgangsmengen (ohne Duplikate).

Praxisbeispiel

Angenommen, es gibt zwei Mengen von Schülern, die die Clubs „Robotik“ und „Programmierung“ besuchen:

Set<String> robotics = Set.of("Alice", "Boris", "Victoria");
Set<String> programming = Set.of("Victoria", "George", "Dora");

Wir müssen die Menge aller Schüler erhalten, die mindestens einen Club besuchen.

Lösung mit der Stream-API

Der direkteste Weg ist, beide Streams zu vereinen und in ein Set zu sammeln:

Set<String> all = Stream.concat(
        robotics.stream(),
        programming.stream()
    ).collect(Collectors.toSet());

System.out.println(all); // [Alice, Boris, Victoria, George, Dora]

Erläuterung:

  • Stream.concat vereint zwei Streams.
  • collect(Collectors.toSet()) sammelt die Elemente in eine Menge (Duplikate werden automatisch entfernt).

Alternative: mehr als zwei Mengen

Wenn wir drei oder mehr Clubs haben, verwenden wir Stream.of und flatMap:

Set<String> math = Set.of("Jane", "Victoria", "Boris");

Set<String> all = Stream.of(robotics, programming, math)
    .flatMap(Set::stream)
    .collect(Collectors.toSet());

System.out.println(all); // [Alice, Boris, Victoria, George, Dora, Jane]

Warum gerade Set?
Weil Set Duplikate automatisch entfernt. Wenn man in eine List sammelt, kommen dieselben Namen mehrfach vor.

2. Operation intersection (Schnittmenge)

Intersection sind die Elemente, die in beiden Mengen gleichzeitig vorhanden sind.

Praxisbeispiel

Finde Schüler, die sowohl in „Robotik“ als auch in „Programmierung“ sind:

Set<String> robotics = Set.of("Alice", "Boris", "Victoria");
Set<String> programming = Set.of("Victoria", "George", "Dora");

Lösung mit der Stream-API:

Set<String> both = robotics.stream()
    .filter(programming::contains)
    .collect(Collectors.toSet());

System.out.println(both); // [Victoria]

Erläuterung:
Wir gehen alle Teilnehmer der „Robotik“ durch und filtern nur diejenigen, die auch in „Programmierung“ sind. Ergebnis: eine Menge mit den Namen, die in beiden Clubs vorkommen.

Alternativer Ansatz (ohne Stream-API)

Man kann die eingebaute Methode retainAll verwenden (sie ändert die aktuelle Menge):

Set<String> intersection = new HashSet<>(robotics);
intersection.retainAll(programming);
System.out.println(intersection); // [Victoria]

Im Kontext der Stream-API legen wir den Fokus jedoch auf Streams.

3. Operation difference (Differenz von Mengen)

Difference sind die Elemente der ersten Menge, die in der zweiten nicht vorkommen.

Praxisbeispiel

Finde Schüler, die nur in „Robotik“ sind, aber nicht in „Programmierung“:

Set<String> robotics = Set.of("Alice", "Boris", "Victoria");
Set<String> programming = Set.of("Victoria", "George", "Dora");

Lösung mit der Stream-API:

Set<String> onlyRobotics = robotics.stream()
    .filter(name -> !programming.contains(name))
    .collect(Collectors.toSet());

System.out.println(onlyRobotics); // [Alice, Boris]

Erläuterung:
Wir filtern die Teilnehmer der „Robotik“ und lassen nur diejenigen übrig, die nicht in „Programmierung“ sind.

Alternativer Ansatz (ohne Stream-API)

Set<String> difference = new HashSet<>(robotics);
difference.removeAll(programming);
System.out.println(difference); // [Alice, Boris]

4. Praxisaufgaben: Verarbeitung von Schülerlisten

Aufgabe 1: Finde Schüler, die nur einen Club besuchen

Wir wollen herausfinden, wer nur „Robotik“ oder nur „Programmierung“ besucht, aber nicht beide gleichzeitig. Das ist die symmetrische Differenz (xor für Mengen):

Set<String> onlyOne = Stream.concat(
        robotics.stream().filter(name -> !programming.contains(name)),
        programming.stream().filter(name -> !robotics.contains(name))
    ).collect(Collectors.toSet());

System.out.println(onlyOne); // [Alice, Boris, George, Dora]

Aufgabe 2: Liste aller eindeutigen Schüler aus mehreren Clubs

Set<String> all = Stream.of(robotics, programming, math)
    .flatMap(Set::stream)
    .collect(Collectors.toSet());

System.out.println(all); // [Alice, Boris, Victoria, George, Dora, Jane]

Aufgabe 3: Finde Schüler, die keinen einzigen Club besuchen

Angenommen, wir haben die Liste aller Schüler der Klasse:

Set<String> allStudents = Set.of("Alice", "Boris", "Victoria", "George", "Dora", "Jane", "Rutger", "Kate");

Wir wollen herausfinden, wer keinen einzigen Club besucht:

Set<String> attendees = Stream.of(robotics, programming, math)
    .flatMap(Set::stream)
    .collect(Collectors.toSet());

Set<String> notInAny = allStudents.stream()
    .filter(name -> !attendees.contains(name))
    .collect(Collectors.toSet());

System.out.println(notInAny); // [Rutger, Kate]

5. Wichtige Hinweise: equals, hashCode und Effizienz

Warum ist es wichtig, equals und hashCode korrekt zu implementieren?

Alle Operationen mit Mengen (Set) hängen von der Korrektheit der Methoden equals und hashCode ab. Wenn Sie Objekte eigener Klassen speichern (z. B. Student), überschreiben Sie diese Methoden unbedingt, andernfalls funktionieren Vergleiche nicht korrekt.

Beispiel:

class Student {
    String name;
    int age;

    // Vergessen Sie nicht, equals und hashCode zu überschreiben!
}

Wenn Sie das nicht tun, werden zwei Schüler mit identischem Namen und Alter für Set als unterschiedliche Objekte angesehen.

Warum sollte man Set statt List verwenden?

  • Die Operation contains ist bei Set schnell (in der Regel konstante Zeit).
  • In einer List erfolgt die Suche linear, was bei großen Kollektionen kritisch sein kann.
  • Für Mengenoperationen (union, intersection, difference) ist Set deutlich effizienter und naheliegender.

6. Typische Fehler beim Umgang mit Mengenoperationen

Fehler Nr. 1: List statt Set für Mengenoperationen verwenden. Wenn Sie Elemente in eine List sammeln, werden Duplikate nicht entfernt und contains ist langsam. Für union/intersection/difference verwenden Sie Set.

Fehler Nr. 2: equals/hashCode für Objekte nicht implementiert. Wenn Sie im Set Objekte eigener Klassen speichern, aber die Methoden equals und hashCode nicht überschreiben, funktionieren Schnittmenge und Differenz „seltsam“ – Objekte, die inhaltlich gleich sind, werden nicht als gleich betrachtet.

Fehler Nr. 3: Änderung der Collection während des Streams. Wenn Sie direkt im Stream die ursprüngliche Set-Collection verändern (z. B. Elemente hinzufügen oder entfernen), erhalten Sie eine ConcurrentModificationException. Arbeiten Sie immer mit einer neuen Menge.

Fehler Nr. 4: Unbeabsichtigter Verlust der Reihenfolge. HashSet garantiert keine Reihenfolge der Elemente. Wenn die Reihenfolge wichtig ist, verwenden Sie LinkedHashSet oder TreeSet.

Fehler Nr. 5: Stream.concat für mehr als zwei Kollektionen verwenden. Stream.concat vereint nur zwei Streams. Für mehr verwenden Sie Stream.of(...) und flatMap.

Fehler Nr. 6: Fehler im Umgang mit null. Mengen mögen null-Werte nicht, besonders wenn Sie Set.of(...) verwenden – es lässt null nicht zu. Verwenden Sie für den Umgang mit null andere Implementierungen oder filtern Sie Werte vorab.

1
Aufgabe
JAVA 25 SELF, Level 32, Lektion 2
Gesperrt
Ermittlung einzigartiger Verdächtiger aus verschiedenen Quellen 🕵️‍♂️
Ermittlung einzigartiger Verdächtiger aus verschiedenen Quellen 🕵️‍♂️
1
Aufgabe
JAVA 25 SELF, Level 32, Lektion 2
Gesperrt
Katalogisierung von Artefakten aus verschiedenen archäologischen Ausgrabungen 🏺
Katalogisierung von Artefakten aus verschiedenen archäologischen Ausgrabungen 🏺
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION