2015-03-20 10 views
5

Auf Seite 140 von Effective Java wird empfohlen, dass eine Methodensignatur mit einem Platzhalter einem Platzhalter mit einem Typparameter vorzuziehen ist, der nur einmal angezeigt wird. Zum BeispielRohtypen und Leistung

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

vorzuziehen

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

jedoch nicht möglich ist, ein Element eines List<?> zu setzen, etwas zu sein (außer null) so Effective Java schlägt eine private Hilfsmethode schreiben zu machen die Signatur mit einem Platzhalter arbeiten.

private static <T> void swapHelper(List<T> list, int i, int j) { 
    list.set(i, list.set(j, list.get(i))); 
} 

public static void swap(List<?> list, int i, int j) { 
    swapHelper(list, i, j); 
} 

jedoch sah ich den Quellcode für Collections.swap und entdeckt, dass die Art und Weise, dass sie um das List<?> Problem bekamrohe Typen zu verwenden war.

public static void swap(List<?> list, int i, int j) { 
    final List l = list; 
    l.set(i, l.set(j, l.get(i))); 
} 

Wir werden darauf hingewiesen, nicht roh Arten in neuem Code zu verwenden (außer in instanceof Schecks). Also, ich würde gerne wissen, was ist der Grund hier? Gibt es einen Leistungsvorteil bei der Verwendung roher Typen hier, anstatt eine private Hilfsmethode aufzurufen? Wenn nicht, gibt es Beispiele, bei denen die Verwendung von Rohtypen die Leistung verbessern kann?

+0

Rohtypen können vermieden werden, indem 'List ' anstelle von 'List' verwendet wird, aber das wäre eine unkontrollierte Umwandlung, die in diesem Fall nicht weniger unsicher ist als der Raw-Typ. – newacct

+0

* "(außer bei Prüfungen)" * Dies ist nicht wahr. "instanceof List " ist in Ordnung und bevorzugt. ;) – Radiodef

+0

@Radiodef Nicht nach Effective Java (2. Ausgabe) Seite 114. –

Antwort

6

Vorzeitige Optimierung ist die Wurzel allen Übels. Sie werden wahrscheinlich feststellen, dass der JIT-Compiler sowohl Ihre Swap-Methode als auch Ihre swapHelper-Methode einbezieht, wenn es sich dabei um Leistungsengpässe handelt. Im Allgemeinen ist der Java JIT Compiler sehr gut in der Erkennung von Leistungsengpässen.

Wenn Sie jedoch an der Leistung interessiert sind, dann schreiben Sie einen Benchmark für die Methode Collections.swap und Ihre Variante, die eine Hilfsmethode verwendet. Das würde Ihnen eine Antwort auf diese Frage geben. Seien Sie sicher, dass Sie genügend viele Iterationen durchführen, damit der JIT-Compiler die Swap-Funktionen als Engpässe erkennt und die Engpässe durch Inlining der Methodenaufrufe optimiert.

Ich würde den Rat von Effective Java anstelle des Codes in Collections.swap folgen. Ich glaube, Sie haben Beweise gefunden, dass Programmierer manchmal Abkürzungen verwenden. Es bedeutet nicht, dass Sie dasselbe tun sollten.

+1

Normalerweise, wenn Leute sagen, dass vorzeitige Optimierung die Wurzel allen Übels ist, befürworten sie, dass die Leute einfachen, klaren Code anstatt verschachtelten Code schreiben, von dem sie denken, dass er schneller laufen könnte. Sie argumentieren fast das Gegenteil.Sie sagen, dass die gefaltete Version mit zwei Methoden hier vorzuziehen ist, da es wichtiger ist, rohe Typen zu vermeiden, als einfachen Code zu schreiben. Was ist das Böse hier? –

+0

Das Übel verwendet eine Version des Codes, der auf die Liste als Rohtyp ohne generische Informationen zugreift. Ja, meiner Meinung nach ist es besser, unformatierte Typen zu vermeiden, als Code mit niedriger Zeilenzahl zu schreiben. Obwohl eine niedrige Zeilenzahl wichtig ist, sind viele Lösungen mit niedrigen Zeilenzahlen ziemlich hackig. Siehe z.B. Antworten in den Programmier-Puzzles & Code-Golf-Website. Sie möchten diese Low-Line-Count-Lösungen nicht unbedingt in Ihrem Produktionscode haben! – juhist

+0

Ich habe Ihre Antwort akzeptiert, da Sie mich davon überzeugt haben, dass Leistung nicht der Grund war, und ich stimme zu, dass wahrscheinlich nur der Autor eine Abkürzung nahm (besonders da die 'Collections' Klasse bereits vor Generika geschrieben wurde). Ich fange jedoch an zu denken, dass es Ausnahmen zur Regel "Niemals rohe Typen verwenden" gibt. Zum Beispiel kann ich nicht sehen, dass der Diamant-Operator in der Liste list = new ArrayList <>(); 'fügt überhaupt etwas hinzu (abgesehen davon, dass der Autor sich wohl fühlt, keine rohen Typen zu verwenden). Ich denke, die 'swapHelper' Methode zu vermeiden, ist ein viel besseres Beispiel. –