Start / Seminare / Java SE Fortgeschrittene Sprachfeatures

Modul

Wildcards

7 Kapitel in diesem Modul-Video · Laufzeit

Vertonung mit synthetischer Stimme · Inhalte redaktionell verantwortet · © 2026 HECKER CONSULTING, alle Rechte vorbehalten

Transkript

Der gesprochene Text dieses Moduls zum Mitlesen, Überfliegen und Durchsuchen. Ein Klick auf einen Zeitstempel springt an die Stelle im Video.

Wildcards

0:00 Wenn Generics als kompliziert gelten, dann liegt das meistens an diesem Thema. Wildcards sind die Fragezeichen, die Sie in Signaturen der Standardbibliothek sehen — und die man üblicherweise überliest, weil man ohnehin nicht recht weiß, was sie bedeuten. Genau das wollen wir hier ändern. Der Schlüssel liegt in einem einzigen Satz: Das Fragezeichen steht nicht für irgendeinen Typ, sondern für einen bestimmten, aber unbekannten Typ.

0:24 Dieser feine Unterschied erklärt fast alles, was an Wildcards zunächst willkürlich wirkt — auch die Frage, warum Sie in manche Listen nichts einfügen dürfen.

Wildcards

0:34 Der letzte Tag beginnt mit dem anspruchsvollsten Modul des Seminars. Wir gehen langsam vor. Zuerst die drei Arten von Wildcards und wo sie Ihnen ohnehin täglich begegnen. Dann jede Art einzeln, mit dem Beispiel, das ihre Existenz begründet. Danach eine Empfehlung, die viele überrascht — nämlich Wildcards aus Rückgabetypen herauszuhalten.

0:54 Und schließlich Wildcard Capture, jene Fehlermeldung mit dem kryptischen capture#1, die einen beim ersten Mal ratlos zurücklässt. Planen Sie für dieses Modul Zeit für Fragen ein. Vier Ziele. Das erste ist begrifflich und trägt alles Weitere. Das zweite ist die Frage, an der man in der Praxis zuerst hängen bleibt: Warum nimmt eine Methode, die eine Liste von Benannt erwartet, keine Liste von Lagerort an, obwohl Lagerort doch ein Benannt ist?

1:20 Das dritte ist eine Merkregel mit vier Buchstaben, die Ihnen die Entscheidung zwischen extends und super abnimmt. Und das vierte ist reine Diagnosefähigkeit — Fehlermeldungen entziffern, die auf den ersten Blick nach einem Compilerfehler aussehen.

Einführung in Wildcards

1:35 Beginnen wir dort, wo Wildcards Ihnen ohnehin täglich begegnen, ohne dass Sie darauf achten: in der Standardbibliothek. Drei Methoden der Schnittstelle List reichen aus, um alle drei Arten zu zeigen — containsAll, addAll und sort. Diese drei Signaturen begleiten uns durch das ganze Modul, und am Ende werden Sie jede von ihnen aus dem Stand erklären können.

1:55 Das ist übrigens ein ganz brauchbarer Prüfstein für sich selbst: Wenn diese drei Zeilen klar sind, sitzt das Thema. Eine Wildcard ist ein Platzhalter für einen bestimmten, aber unbekannten Typ. Ein Bild dazu: Denken Sie an ein Paket ohne Aufschrift. Es ist nicht leer und es enthält auch nicht beliebig Verschiedenes — der Inhalt ist durchaus eindeutig, Sie wissen nur nicht, was es ist.

2:18 Deshalb dürfen Sie auch nichts hineinlegen: Sie könnten ja das Falsche dazupacken. Genau das ist der Unterschied zu einer Liste von Object, und diesen Unterschied nehmen wir uns gleich im Detail vor. Es gibt drei Arten: unbeschränkt, nach oben und nach unten beschränkt. Diese drei Signaturen sind der rote Faden des ganzen Moduls.

2:38 containsAll nimmt eine Sammlung mit beliebigem Elementtyp — logisch, denn zum Nachschauen muss man nichts über den Typ wissen. addAll nimmt eine Sammlung von Untertypen; auch das wird gleich einleuchten, denn die Methode liest daraus. Und sort nimmt einen Comparator für Obertypen, weil die Methode ihm Elemente hineingibt.

2:57 Jede der drei Signaturen ist nicht willkürlich, sondern folgt aus der Frage, was die Methode mit dem Parameter tut. Diese Frage ist der Kern des Moduls. Wozu also das Ganze? Wildcards machen Methoden flexibler in dem, was sie annehmen — das ist der offensichtliche Nutzen. Der weniger offensichtliche ist mir wichtiger: Sie sagen zugleich, wie die Methode mit dem Argument umgeht. Wer extends liest, weiß, dass gelesen wird.

3:24 Wer super liest, weiß, dass geschrieben wird. Das ist Dokumentation, die der Compiler durchsetzt. Und noch ein Hinweis zur Verortung: Wildcards gehören in Signaturen. In Feldern und lokalen Variablen haben sie fast nie etwas zu suchen — dort sind sie meist ein Zeichen für ein anderes Problem. Vier Punkte gleich vorweg, damit Sie sie im Verlauf wiedererkennen. Der erste ist die begriffliche Verwechslung, die wir eben besprochen haben.

3:51 Der zweite betrifft den Ort — Wildcards in eigenen Feldtypen sind fast immer falsch. Der dritte ist tückisch und begegnet uns im Kapitel über Capture wieder: Zwei Fragezeichen in derselben Signatur meinen nicht denselben Typ, auch wenn sie gleich aussehen. Und der vierte ist der häufigste Grund für falsche Signaturen: Die Schranke nach Gefühl setzen, statt zu fragen, in welche Richtung die Daten fließen.

Unbeschränkte Wildcards

4:14 Fangen wir mit dem einfachsten Fall an. Manchmal interessiert der Elementtyp überhaupt nicht — die Methode tut etwas, das vom Inhalt völlig unabhängig ist. Zählen zum Beispiel, oder auf Leerheit prüfen. Für solche Fälle gibt es das nackte Fragezeichen ohne jede Schranke. Und ausgerechnet an diesem einfachen Fall lässt sich das wichtigste Missverständnis dieses ganzen Moduls am besten aufklären: nämlich die Verwechslung mit einer Liste von Object.

4:40 Die beiden sehen ähnlich aus und sind es nicht. Eine unbeschränkte Wildcard passt, wenn die Methode über das Typargument nichts wissen muss. Die Größe einer Liste hängt nicht davon ab, was darin liegt — das ist das Standardbeispiel. Sie könnten dafür auch einen Typparameter deklarieren, und es würde funktionieren. Aber dieser Typparameter käme in der Signatur nur ein einziges Mal vor und stellte damit keine Beziehung her. Er wäre reines Rauschen.

5:07 Das Fragezeichen sagt dasselbe, nur ehrlicher: Hier ist ein Typ im Spiel, und er ist für diese Methode ohne Belang. Hier stehen beide Fassungen direkt untereinander, und sie leisten exakt dasselbe. Beide nehmen Listen mit beliebigem Elementtyp entgegen, beide liefern dieselbe Zahl. Der Unterschied ist rein sprachlich — und trotzdem nicht bedeutungslos. Die untere Fassung teilt dem Leser mit: Hier gibt es nichts über den Typ zu wissen.

5:34 Die obere lässt ihn zunächst suchen, wo dieses E denn noch auftaucht. Das ist eine Kleinigkeit, aber sie summiert sich. Die Faustregel dazu steht in der Fußzeile: Ein Typparameter, der nur einmal vorkommt, ist meistens fehl am Platz. Und jetzt das Missverständnis, das ich vorhin angekündigt habe. Eine Liste von Object und eine Liste von Fragezeichen sind nicht dasselbe.

5:57 Eine Liste von Object enthält beliebige Objekte, auch bunt gemischt — Zeichenketten neben Zahlen neben Artikeln. Eine Liste von Fragezeichen enthält dagegen Objekte eines einzigen, aber unbekannten Typs. Genau deshalb dürfen Sie in sie nichts einfügen. Der Compiler kann nicht prüfen, ob Ihr Element zum unbekannten Typ passt. Die einzige Ausnahme ist null, denn null passt zu jedem Referenztyp.

6:22 Diese Gegenüberstellung ist die Antwort auf eine Frage, die in jedem Kurs kommt: Warum kann ich in eine Liste von Fragezeichen nichts einfügen? Die Tabelle beantwortet sie Zeile für Zeile. Aber die praktisch wichtigste Zeile ist die letzte, und die wird oft übersehen: Eine Liste von Object nimmt keine Liste von String an.

6:40 Genau deshalb ist die Wildcard überhaupt nötig — ohne sie könnten Sie schlicht keine Methode schreiben, die Listen beliebigen Inhalts entgegennimmt. Der Verzicht auf das Einfügen ist der Preis dafür, und er ist meistens keiner. Eine kleine Aufgabe mit klarem Erkenntnisgewinn. Sie ersetzen einen Typparameter, der nichts beiträgt, durch eine unbeschränkte Wildcard.

7:01 Und dann kommt der lehrreiche Teil: Versuchen Sie, ein Element einzufügen. Die Fehlermeldung, die Sie dabei bekommen, erklärt den Unterschied zu einer Liste von Object besser als jede Tabelle — sie nennt nämlich einen Typ, den Sie so nirgends geschrieben haben. Genau dieser Typ wird uns im Kapitel über Capture wieder begegnen. Merken Sie sich die Meldung, wir kommen darauf zurück.

7:23 Der erste Punkt ist das Missverständnis von eben, das ich für das folgenreichste in diesem ganzen Modul halte. Der zweite ist der Typparameter ohne Beziehung. Der dritte ist eine Reaktion, die ich häufig sehe: Wenn add nicht funktioniert, wird die Wildcard für kaputt gehalten — dabei tut sie genau das, wofür sie da ist.

7:41 Und der vierte ist der schlimmste Ausweg: einen Rohtyp verwenden, um dem Problem aus dem Weg zu gehen. Damit schalten Sie die Typprüfung ganz ab, und in Modul acht sehen wir, was das anrichten kann.

Obere Schranken

7:53 Jetzt zu dem Fall, der Sie in der Praxis zuerst einholt. Sie schreiben eine Methode, die eine Liste von Benannt erwartet, übergeben eine Liste von Lagerort — und der Compiler lehnt ab, obwohl Lagerort doch offensichtlich ein Benannt ist. Diese Fehlermeldung hat fast jeder schon gesehen, und die übliche Reaktion ist Verwirrung oder ein Umkopieren der Liste. Beides ist unnötig.

8:15 Klären wir, was dahintersteckt — und lernen dabei gleich die Merkregel kennen, die den Rest des Moduls trägt. Die Ursache heißt Invarianz. Generics in Java sind invariant: Eine Liste von Lagerort ist kein Untertyp einer Liste von Benannt, auch wenn Lagerort ein Untertyp von Benannt ist. Das wirkt zunächst wie eine Schikane, hat aber einen guten Grund, den wir uns im nächsten Modul im Detail ansehen.

8:38 Kurz gesagt: Wäre es anders, könnten Sie in eine Liste von Lagerorten etwas anderes hineinlegen. Die Lösung ist eine nach oben beschränkte Wildcard — sie stellt die Flexibilität gezielt an der Stelle her, an der sie gebraucht wird, und nur dort. Hier stehen beide Fassungen untereinander. Die obere nimmt nur exakt eine Liste von Benannt — praktisch ist das fast nutzlos, denn niemand hat solche Listen.

9:02 Die untere nimmt jede Liste, deren Elementtyp Benannt umsetzt. Der Unterschied ist ein einziges Sprachkonstrukt in der Signatur; im Rumpf ändert sich nichts. Und achten Sie auf die Fußzeile, dort steht die Begründung: Wir lesen aus der Liste. Deshalb ist extends hier richtig. Diese Verbindung zwischen Datenrichtung und Schranke ist der Kern des nächsten Abschnitts.

9:25 Und damit zur Merkregel, die Ihnen die Entscheidung abnimmt: PECS — producer extends, consumer super. Denken Sie es aus der Sicht der Methode. Liefert der Parameter Daten, ist er ein Produzent, und dann gehört extends daran. Nimmt er Daten entgegen, ist er ein Konsument, und dann super. Vier Buchstaben, die eine erstaunlich schwierige Frage entscheiden.

9:46 Und wenn Sie sich das nächste Mal die Signatur von addAll ansehen: Die Methode liest aus der übergebenen Sammlung, also extends. Es passt. Was dürfen Sie mit einer nach oben beschränkten Wildcard? Lesen auf jeden Fall, denn jedes Element ist mindestens vom Schrankentyp — das genügt für den Schleifendurchlauf. Einfügen dürfen Sie nicht, und der Grund ist derselbe wie bei der unbeschränkten Wildcard: Der genaue Elementtyp bleibt unbekannt.

10:13 Für den Aufrufer heißt das: Er darf jede Liste passender Untertypen übergeben. Und noch ein Hinweis, der in der Praxis nützlich ist: Die Schranke muss kein Typparameter sein, ein konkreter Typ tut es auch. In dieser Aufgabe reparieren Sie eine zu eng deklarierte Methode. Der Hinweis ist wichtig: Legen Sie zwei Untertypen an, nicht nur einen.

10:33 Erst mit zwei verschiedenen Untertypen wird sichtbar, was Sie gewinnen — nämlich eine Methode, die für beide funktioniert, ohne dass Sie sie doppelt schreiben müssen. Mit nur einem Untertyp könnte man ja auch einfach den konkreten Typ in die Signatur schreiben. Der Nutzen von Wildcards zeigt sich immer erst bei Vielfalt.

10:52 Der erste Punkt ist eine Reaktion, die ich oft sehe: Invarianz für einen Fehler halten und die Liste kurzerhand umkopieren. Das funktioniert, kostet aber Speicher und Zeit für ein Problem, das eine Signaturänderung löst. Der zweite ist der Versuch, in eine extends-Liste einzufügen — dann war die Analyse der Datenrichtung falsch.

11:11 Der dritte ist eine zu hoch angesetzte Schranke, nach der im Rumpf nichts mehr aufrufbar ist. Und der vierte betrifft eine echte Grenze: Mehrere Obergrenzen kann eine Wildcard nicht tragen, dafür brauchen Sie einen Typparameter.

Untere Schranken

11:25 Kommen wir zur zweiten Hälfte unserer Merkregel. Untere Schranken sind deutlich seltener als obere und deshalb auch ungewohnter — viele Entwickler haben sie noch nie selbst geschrieben. Die Logik dahinter ist aber genau spiegelbildlich zu dem, was wir eben gesehen haben. Es geht um Parameter, in die die Methode etwas hineingibt, statt aus ihnen zu lesen.

11:44 Wenn Sie den vorigen Abschnitt verstanden haben, ist dieser hier eine Fingerübung — man muss nur die Richtung umdrehen. Eine nach unten beschränkte Wildcard schreibt sich mit super und steht für den Typ selbst oder einen seiner Obertypen. Das klingt zunächst rückwärts, wird aber sofort einleuchtend, wenn man an ein Beispiel denkt.

12:03 Wenn Ihre Methode Zahlen verarbeitet, dann kann jeder, der mit allgemeineren Objekten umgehen kann, das auch — wer alles verarbeiten kann, kann auch Zahlen verarbeiten. Deshalb nimmt sort einen Comparator für Obertypen entgegen: Ein Vergleicher, der mit allgemeineren Objekten zurechtkommt, taugt auch für die speziellen.

12:22 Der Vergleich macht es konkret. Die obere Fassung verlangt einen Verarbeiter für genau den Elementtyp. Übergeben Sie eine Sammlung von Integer, brauchen Sie einen Verarbeiter für Integer — einer für Number wird abgelehnt, obwohl er die Aufgabe offensichtlich erfüllen könnte. Die untere Fassung mit super lässt genau das zu. Das ist der praktische Nutzen: Ihre Methode wird an der Aufrufstelle brauchbarer, ohne im Rumpf etwas zu verlieren.

12:47 Sie geben ja nur Elemente hinein, und dafür genügt ein Verarbeiter, der mindestens diesen Typ akzeptiert. Diese Tabelle ist Ihr Nachschlagewerk für den Alltag. Produzent — extends, Lesen erlaubt. Konsument — super, Einfügen erlaubt. Und dann die dritte Zeile, die die wichtigste Ausnahme benennt: Wenn ein Parameter beides ist, also gelesen und geschrieben wird, dann darf dort keine Wildcard stehen.

13:11 Dann brauchen Sie einen Typparameter. Diese Regel wird uns im Kapitel über Capture noch beschäftigen, denn die Verletzung dieser Regel ist die häufigste Ursache für jene kryptischen Fehlermeldungen. Der Prüfstein für diese Aufgabe steht im Hinweis: Übergeben Sie einen Verarbeiter für Object an eine Sammlung von Integer. Wenn das übersetzt, sitzt die untere Schranke.

13:33 Die Fähigkeit, die Sie dabei üben, ist nicht das Schreiben von super, sondern das Erkennen der Datenrichtung. Fragen Sie sich bei jedem Parameter: Hole ich hier etwas heraus oder gebe ich etwas hinein? Wenn Sie das beantworten können, schreibt sich die Signatur von selbst. Der erste Punkt ist der häufigste: super und extends vertauschen, weil beides irgendwie zu passen scheint. Das Gegenmittel ist die konsequente Frage nach der Datenrichtung.

14:00 Der zweite ist ein Perspektivfehler — PECS liest man aus der Sicht der Methode, nicht des Aufrufers; wer die Perspektive wechselt, dreht die Regel um. Der dritte ist eine überflüssige Öffnung: super an einem Parameter, aus dem nur gelesen wird. Und der vierte ist die Ausnahme von eben — Wildcard, wo ein Typparameter hingehört.

Keine Wildcards im Rückgabetyp

14:20 Ein kurzes, aber wichtiges Kapitel. Bisher haben Wildcards ausschließlich Gutes bewirkt: Sie haben Signaturen geöffnet und Methoden brauchbarer gemacht. Im Rückgabetyp kehrt sich das vollständig um — dort richten sie Schaden an, und zwar beim Aufrufer, während der Autor der Methode nichts davon merkt. Der Grund ist derselbe, aus dem sie in Parametern nützen, nur mit umgekehrtem Vorzeichen.

14:43 Das ist ein Muster, das sich zu merken lohnt, weil es auch außerhalb von Generics vorkommt. In Parametern schaffen Wildcards Flexibilität, weil sie weniger verlangen. Im Rückgabetyp bewirken sie das Gegenteil: Sie verwerfen die genaue Typinformation, die der Aufrufer braucht. Wer Ihre Methode aufruft, weiß dann nur noch, dass irgendein Untertyp zurückkommt — und kann damit fast nichts anfangen.

15:08 Merken Sie sich deshalb die Einschränkung: Die PECS-Regel gilt ausdrücklich nur für Parameter. Für Rückgabetypen gilt eine andere und viel einfachere Regel: so genau wie möglich. Vergleichen Sie die beiden Signaturen. Die obere nutzt einen Typparameter, die untere Wildcards. Beide sehen für sich betrachtet vernünftig aus, und beide übersetzen.

15:29 Der Unterschied zeigt sich erst in der letzten Zeile, bei der Zuweisung. Mit der oberen Fassung funktioniert sie, mit der unteren nicht — obwohl Sie als Leser genau sehen können, dass dort Lagerorte entstehen. Der Compiler kann es nicht mehr sehen, weil die Signatur diese Information verworfen hat. Das ist der ganze Punkt dieses Kapitels.

15:50 Warum ist das so teuer? Weil die Information vorhanden war und mutwillig weggeworfen wurde. Der Aufrufer weiß nur noch, dass irgendein Untertyp zurückkommt. Jede Zuweisung an einen konkreten Typ scheitert oder braucht eine Umwandlung — und mit der Umwandlung sind Sie wieder bei den Problemen, die Generics eigentlich abschaffen sollten.

16:09 Ein Typparameter dagegen überträgt die Information sauber bis zur Aufrufstelle. Er verbindet Parameter und Rückgabetyp, und genau das ist seine Aufgabe. Schreiben Sie beide Fassungen nebeneinander und rufen Sie beide auf. Der Hinweis ist entscheidend: Der Unterschied zeigt sich ausschließlich an der Aufrufstelle. In der Methode selbst merken Sie nichts davon, und deshalb entstehen solche Signaturen auch — der Autor sieht das Problem nicht.

16:35 Was Sie hier lernen, ist eine Perspektivübung: Beim Entwerfen einer Signatur immer auch die Seite des Aufrufers einnehmen. Das gilt weit über Wildcards hinaus. Der erste Punkt ist die Übergeneralisierung von PECS auf Rückgabetypen. Der zweite ist die übliche Reparatur an der falschen Stelle: eine Umwandlung beim Aufrufer ergänzen, statt die Signatur zu korrigieren — das behebt das Symptom für genau einen Aufrufer.

16:59 Der dritte ist verwandt: var beim Aufrufer schiebt das Problem nur eine Zeile weiter. Und der vierte ist der teuerste, weil er sich nicht mehr korrigieren lässt: Wildcards als Rückgabetyp in einer öffentlichen Schnittstelle festzuschreiben.

Wildcard Capture

17:13 Und nun zu der Fehlermeldung, die diesem Thema seinen Ruf eingebracht hat. capture#1 of ? — ein Typname, den niemand geschrieben hat, in einer Meldung, die beim ersten Mal nach einem Compilerfehler aussieht. Sie ist keiner. Der Compiler tut hier genau das Richtige, er tut es nur mit einem Vokabular, das im Quelltext nirgends vorkommt.

17:33 Wenn Sie verstehen, was dahintersteckt, wird diese Meldung vom Ärgernis zur Diagnose — sie sagt Ihnen nämlich ziemlich genau, was an Ihrer Signatur nicht stimmt. Was passiert da? Um einen Typ mit Wildcard prüfen zu können, braucht der Compiler etwas Konkretes, mit dem er rechnen kann. Also ersetzt er die Wildcard intern durch eine temporäre Typvariable und gibt ihr einen Namen — capture#1 of ?, capture und eine Nummer.

17:59 Danach führt er seine übliche Prüfung durch. Der Fehler entsteht typischerweise, weil ein Wert vom Typ Object nicht in diese engere temporäre Typvariable passt. Klingt abstrakt, ist es aber nicht — das nächste Beispiel macht es greifbar. Sehen Sie sich diese vier Zeilen an. Die Methode entnimmt das erste Element und hängt es hinten wieder an — eine Rotation.

18:21 Als Mensch sehen Sie sofort: Das ist sicher, es ist ja dieselbe Liste. Der Compiler sieht das anders. Das entnommene Element hat für ihn den Typ Object, denn genauer kann er es aus einer Liste von Fragezeichen nicht bestimmen. Und einzufügen wäre etwas vom Typ capture#1 — also enger als Object. Deshalb die Ablehnung. Der Compiler ist hier nicht dumm, er ist nur vorsichtig.

18:45 Wenn Ihnen so eine Meldung begegnet, hilft dieses Vorgehen. Suchen Sie zuerst den Parameter mit der Wildcard, lesen Sie capture als dessen temporäre Typvariable und prüfen Sie, welchen Typ der gelesene Wert tatsächlich hat. Aber der eigentliche Schritt ist der vierte, und der ist eine Diagnose: Liest und schreibt die Methode aus demselben Argument? Wenn ja, dann war die Wildcard von Anfang an falsch.

19:08 Dann ist die Lösung nicht ein Trick, sondern ein Typparameter — genau der Fall aus der PECS-Tabelle von vorhin. Ein zweiter Weg, in dieselbe Falle zu tappen, sieht so aus. Die obere Signatur hat zwei Fragezeichen, und die Versuchung ist groß, sie für denselben Typ zu halten. Sie sind es nicht — sie sind vollkommen unabhängig.

19:27 Der Aufrufer darf eine Liste von Artikeln und einen Verarbeiter für Zeichenketten übergeben, und die Signatur erlaubt das ausdrücklich. Die untere Fassung repariert das: Ein Typparameter verbindet beide Stellen, und die Schranken folgen PECS — die Liste liefert, also extends; der Verarbeiter nimmt entgegen, also super. In dieser Aufgabe lösen Sie eine Capture-Meldung auf, und der Hinweis beschreibt das Vorgehen: Notieren Sie vorher, welche Datenrichtungen der Parameter hat.

19:56 Wenn Sie das getan haben, ergibt sich die Antwort von selbst — Wildcard oder Typparameter ist keine Geschmacksfrage, sondern eine Folge der Analyse. Diese Diagnosefähigkeit ist der eigentliche Ertrag des Kapitels. Sie werden solchen Meldungen wieder begegnen, und dann wissen Sie, wo Sie anfangen. Der erste Punkt ist der naheliegende Reflex: var einsetzen und hoffen. Das löst das Problem nicht, es benennt es nur anders.

20:21 Der zweite ist die Annahme, zwei Fragezeichen meinten denselben Typ — wir haben eben gesehen, dass das nicht so ist. Der dritte ist die brachiale Reparatur mit einer Umwandlung auf Object; sie bringt Sie durch den Compiler und in Modul acht zurück, wenn wir über Heap Pollution sprechen. Und der vierte ist eine Haltungsfrage: Capture ist kein Compilerfehler, sondern eine korrekte und in dieser Situation berechtigte Prüfung.

Leitlinien für den Alltag

20:46 Zum Abschluss fassen wir dieses anspruchsvolle Modul in eine Handvoll Leitlinien. Es gibt einen Satz der Java-Autoren, der das Ganze überraschend knapp auf den Punkt bringt, und daneben ein Vorgehen aus fünf Fragen, mit dem Sie praktisch jede Signatur entscheiden können. Beides zusammen passt auf einen Zettel und ersetzt im Alltag das Nachschlagen.

21:05 Was heute lange gedauert hat, wird damit zu einer Entscheidung, die Sie beim Schreiben nebenbei treffen. Die Leitlinie stammt aus einem alten Buch der Java-Erfinder und lautet sinngemäß: Wildcards verwenden, wo es geht, denn sie lesen sich besser als mehrere Typparameter. Ein Typparameter ist nötig, sobald er zwei Parameter miteinander oder einen Parameter mit dem Rückgabetyp in Beziehung setzt.

21:28 In einem Satz: Wildcards, wo man kann — Typparameter, wo man muss. Das ist die Zusammenfassung dieses ganzen Moduls, und sie passt in eine Zeile. Der Weg dorthin war der längere Teil. Diese fünf Fragen decken praktisch jede Signatur ab, die Ihnen im Alltag begegnet. Muss die Methode überhaupt etwas über den Typ wissen? Nein — dann unbeschränkte Wildcard.

21:51 Wird nur gelesen? Obere Schranke. Wird nur geschrieben? Untere Schranke. Wird beides getan oder hängen zwei Stellen zusammen? Dann Typparameter. Was mir daran gefällt: Die Reihenfolge der Fragen ist zugleich die Reihenfolge der Häufigkeit. Die einfachen Fälle klären sich zuerst, und der aufwendigste steht am Ende. Vier Grenzen zum Abschluss. Die erste treffen Sie in der Praxis am häufigsten: Eine Wildcard trägt höchstens eine Schranke.

22:20 Brauchen Sie zwei Obergrenzen — etwa benannt und vergleichbar —, führt kein Weg an einem Typparameter vorbei. Die zweite: Obere und untere Schranke gleichzeitig gibt es nicht; wer das braucht, hat die Signatur falsch geschnitten. Die dritte und vierte fassen zusammen, was wir zu Rückgabetypen gesagt haben. Diese vier Punkte sind es wert, im Hinterkopf zu bleiben, weil sie in Fehlermeldungen selten deutlich benannt werden.

22:45 Zum Abschluss eine Aufgabe an Ihrem eigenen Code. Nehmen Sie drei generische Signaturen und bewerten Sie sie systematisch. Der Hinweis nennt die Reihenfolge: erst die Datenrichtung notieren, dann über die Schranke entscheiden. Wichtig ist mir dabei, dass eine bestätigte Signatur ein genauso gültiges Ergebnis ist wie eine geänderte.

23:04 Es geht nicht darum, überall Wildcards einzuziehen, sondern darum, die vorhandenen Entscheidungen einmal bewusst nachvollzogen zu haben. Der erste Punkt ist die Übertreibung in die eine Richtung: Wildcards überall, weil sie kürzer aussehen. Der zweite ist die Übertreibung in die andere: Typparameter, die nichts miteinander in Beziehung setzen.

23:24 Der dritte ist die Grenze von eben — zwei Schranken an einer Wildcard gibt es nicht. Und der vierte ist der Grund, warum sich das sorgfältige Nachdenken lohnt: In einer öffentlichen Schnittstelle lässt sich diese Entscheidung nachträglich nicht mehr ändern, ohne fremden Code zu brechen. Vier Sätze zum Mitnehmen. Das Fragezeichen steht für einen bestimmten, aber unbekannten Typ — daraus folgt alles, auch das Einfügeverbot.

23:48 PECS entscheidet die Schranke, aus der Sicht der Methode gelesen. Im Rückgabetyp haben Wildcards nichts verloren, weil sie dort Information vernichten statt Flexibilität zu schaffen. Und eine Meldung mit capture bedeutet fast immer: Hier wird aus demselben Argument gelesen und geschrieben. Im nächsten Modul schauen wir unter die Oberfläche und klären, warum das alles überhaupt so gebaut ist.

Lieber mit Trainer? Dieses Modul ist Teil unserer Team-Schulungen — mit Übungen, Ihrem eigenen Code und Fragen, die ein Video nicht beantwortet. Mehr erfahren →