Warum einen Platzhalter einem Typdiskriminator in einer Java-API vorziehen (Re: Effective Java)

8

Im Abschnitt "Generika" von Blochs "Effective Java" (das für alle das "kostenlose" Kapitel ist: http://java.sun.com/docs/books/effective/generics.pdf ) sagt er:

Wenn ein Typparameter in einer Methodendeklaration nur einmal vorkommt, ersetzen Sie ihn durch einen Platzhalter.

(Siehe Seite 31-33 dieses PDFs)

Die fragliche Unterschrift lautet:

public static void swap(List<?> list, int i, int j)

vs.

public static void swap(List<E> list, int i, int j)

Anschließend wird eine statische private "Hilfsfunktion" mit einem tatsächlichen Typparameter verwendet, um die Arbeit auszuführen. Die Signatur der Hilfsfunktion entspricht genau der der zweiten Option.

Warum ist der Platzhalter vorzuziehen, da Sie KEINEN Platzhalter verwenden müssen, um die Arbeit trotzdem zu erledigen? Ich verstehe, dass in diesem Fall, da er die Liste ändert und Sie einer Sammlung keinen unbegrenzten Platzhalter hinzufügen können, warum überhaupt verwenden?

Michael Campbell
quelle

Antworten:

5

Warum ist der Platzhalter vorzuziehen?

Ich glaube, Josh sagt es klar:

In einer öffentlichen API ist der [Platzhalter] besser, weil er einfacher ist.

Das heißt, für die Benutzer der API. Die geringe zusätzliche Komplexität in der Implementierung ist von außen nicht sichtbar. Da die Implementierung nur einmal geschrieben wurde, die API jedoch häufig von vielen verschiedenen Personen verwendet werden kann, ist die Vereinfachung der API auf Kosten einer etwas komplexeren Implementierung immer noch ein Gewinn.

> warum überhaupt verwenden?

Du meinst, warum ist es besser als

public static void swap(List list, int i, int j)

? Da letzteres Generika insgesamt verlieren würde, würde der Compiler alle generischen Typprüfungen weglassen und uns erlauben, schlampigen Code zu schreiben. Ich denke, es ist besser, generische Typensignaturen zu verwenden, auch wenn sie so allgemein sind, nur um die Gewohnheit aufrechtzuerhalten.

Update reflektiert den Kommentar unten

Sie haben die generische Parameterdeklaration aus der zweiten Signatur vergessen, richtig sollte es sein

public static <E> void swap(List<E> list, int i, int j)

Das heißt, <E>erscheint zweimal, ohne zusätzlichen Nutzen, und <?>erscheint nur einmal in der ersten Signatur. Deshalb ist es einfacher.

Péter Török
quelle
1
Nein, warum ist Swap (Liste <?>, ...) dem Swap (Liste <E>, ...) vorzuziehen. Ich verstehe nicht, warum es in jedem Kontext einfacher ist.
Michael Campbell
1
Sehen Sie den Nutzen nicht wirklich. Damit ein Benutzer die Swap-Methode verwenden kann, wird entweder die Version public static <E> void swap (Liste <E> list, int i, int j) oder public static void swap (List <?> List, int i, int) aufgerufen j) würde genau das gleiche tun, nämlich tauschen (myList, 0, 1). Ob das <E> zweimal erscheint oder stattdessen einen Platzhalter hat, spielt meiner Meinung nach keine Rolle. Vielleicht fehlt mir etwas?
Will
1
@Will lesen Sie vor dem Aufruf (normalerweise) die API-Deklaration. Die Wildcard-Version der Deklaration ist für unser Gehirn (geringfügig) einfacher zu interpretieren.
Péter Török
1
ok, es geht also wirklich um diese winzige Vereinfachung. Vielen Dank.
Wird
2
Ich muss @Will zustimmen, die Vereinfachung ist so klein, dass es sich kaum lohnt, sie zu machen.
Andres F.