PMD
sagt mirEffizienz: switch-Anweisungen über if-Anweisungen
Ein Schalter mit weniger als 3 Zweige ineffizient ist, verwenden Sie eine if-Anweisung statt.
Warum ist das so? Warum 3? Wie definieren sie Effizienz?
PMD
sagt mirEffizienz: switch-Anweisungen über if-Anweisungen
Ein Schalter mit weniger als 3 Zweige ineffizient ist, verwenden Sie eine if-Anweisung statt.
Warum ist das so? Warum 3? Wie definieren sie Effizienz?
Da eine switch
-Anweisung mit zwei speziellen JVM-Anweisungen kompiliert wird, die lookupswitch
und sind. Sie sind nützlich, wenn Sie mit vielen Fällen arbeiten, aber sie verursachen einen Overhead, wenn Sie nur wenige Zweige haben.
Eine if/else
Anweisung ist stattdessen in typische je
jne
... Ketten zusammengefasst, die schneller sind, aber viel mehr Vergleiche erfordern, wenn sie in einer langen Kette von Zweigen verwendet werden.
Sie können den Unterschied sehen, indem Sie sich den Byte-Code ansehen, in jedem Fall würde ich mich nicht um diese Probleme kümmern, wenn irgendetwas ein Problem werden könnte, dann wird JIT sich darum kümmern.
Praxisbeispiel:
switch (i)
{
case 1: return "Foo";
case 2: return "Baz";
case 3: return "Bar";
default: return null;
}
in kompilierten:
L0
LINENUMBER 21 L0
ILOAD 1
TABLESWITCH
1: L1
2: L2
3: L3
default: L4
L1
LINENUMBER 23 L1
FRAME SAME
LDC "Foo"
ARETURN
L2
LINENUMBER 24 L2
FRAME SAME
LDC "Baz"
ARETURN
L3
LINENUMBER 25 L3
FRAME SAME
LDC "Bar"
ARETURN
L4
LINENUMBER 26 L4
FRAME SAME
ACONST_NULL
ARETURN
Während
if (i == 1)
return "Foo";
else if (i == 2)
return "Baz";
else if (i == 3)
return "Bar";
else
return null;
in
zusammengestelltL0
LINENUMBER 21 L0
ILOAD 1
ICONST_1
IF_ICMPNE L1
L2
LINENUMBER 22 L2
LDC "Foo"
ARETURN
L1
LINENUMBER 23 L1
FRAME SAME
ILOAD 1
ICONST_2
IF_ICMPNE L3
L4
LINENUMBER 24 L4
LDC "Baz"
ARETURN
L3
LINENUMBER 25 L3
FRAME SAME
ILOAD 1
ICONST_3
IF_ICMPNE L5
L6
LINENUMBER 26 L6
LDC "Bar"
ARETURN
L5
LINENUMBER 28 L5
FRAME SAME
ACONST_NULL
ARETURN
Jack danke. Das ist eine wundervolle Antwort. Nebenbei, was hast du benutzt, um '.class' Dateien zu sehen? – JAM
Es ist ein Plugin für Eclipse, wenn ich mich richtig erinnere sollte es dieses sein: http://andrei.gmxhome.de/bytecode/index.html – Jack
@JAM: Ich glaube, Sie auch [javap] (http verwenden: // docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/javap.html). – RanRag
Obwohl bei Verwendung eines Switches im Vergleich zur Verwendung einer if-Anweisung geringe Effizienzgewinne auftreten, wären diese Gewinne unter den meisten Umständen vernachlässigbar. Und jeder Quellcodeleser, der es wert ist, würde erkennen, dass micro-optimizations der Klarheit des Codes untergeordnet sind.
Sie sagen, dass eine if-Anweisung sowohl einfacher zu lesen ist als auch weniger Zeilen Code als eine switch-Anweisung benötigt, wenn der Schalter signifikant kurz ist.
Vom PMD website:
TooFewBranchesForASwitchStatement: Switch-Anweisungen werden indended verwendet werden, um komplexe Verzweigungsverhalten zu unterstützen. Die Verwendung eines Schalters für nur wenige Fälle ist nicht ratsam, da Schalter nicht so einfach zu verstehen sind wie Wenn-Dann-Anweisungen. In diesen Fällen verwenden Sie die Anweisung if-then, um die Lesbarkeit des Codes zu erhöhen.
Ich glaube, es mit der Art und Weise zu tun, dass ein Schalter, und einem if/else unten kompiliert.
Nehmen wir an, es dauert 5 Berechnungen, um eine switch-Anweisung zu verarbeiten. Sagen Sie, eine if-Anweisung benötigt zwei Berechnungen. Weniger als 3 Optionen in Ihrem Switch wären 4 Berechnungen in ifs gegenüber 5 in switches. Der Overhead bleibt jedoch in einem Switch konstant, so dass, wenn es 3 Auswahlmöglichkeiten hat, ifs 3 * 2 verarbeitet wird, während 5 noch für den Switch sind.
Die Gewinne bei der Betrachtung von Millionen von Berechnungen sind extrem vernachlässigbar. Es ist eher eine Frage von "Dies ist der bessere Weg, es zu tun" als alles, was Sie beeinflussen könnte. Es würde nur so etwas tun, das in einer ganzen Iteration millionenfach an dieser Funktion vorbeigeht.
Warum ist das?
Verschiedene Sequenzen von Anweisungen werden verwendet, wenn der Code vom JIT-Compiler (endlich) in nativen Code kompiliert wird. Ein Switch wird durch eine Sequenz nativer Anweisungen implementiert, die eine indirekte Verzweigung ausführen. (Die Sequenz lädt typischerweise eine Adresse aus einer Tabelle und verzweigt dann zu dieser Adresse.) Ein if/else wird als Anweisungen implementiert, die die Bedingung (wahrscheinlich einen Vergleichsbefehl), gefolgt von einem bedingten Verzweigungsbefehl, auswerten.
Warum 3?
Es ist eine empirische Beobachtung, nehme ich an Basis der generierten nativen Code Anweisungen zum Analysieren und/oder Benchmarking. (Oder möglicherweise nicht. Um absolut sicher zu sein, müssten Sie den Autor (die Autoren) dieser PMD-Regel fragen, wie sie diese Nummer abgeleitet haben.)
Wie definieren sie Effizienz?
Zeitaufwand für die Ausführung der Anweisungen.
Ich würde persönlich mit dieser Regel in Frage stellen ... oder genauer gesagt mit der Nachricht. Ich denke, es sollte sagen, dass eine Aussage einfacher und lesbarer ist als ein Schalter mit 2 Fällen. Das Effizienzproblem ist zweitrangig und wahrscheinlich irrelevant.
Was ist PMD? ? ? – jmort253
PMD scannt Java-Quellcode und sucht nach möglichen Problemen wie möglichen Fehlern, totem Code, suboptimalem Code, überkomplizierten Ausdrücken und doppeltem Code. (Bewegen Sie die Maus über die Tags) – Chords
Es sollte sich auch nach Grammatik durchsuchen lassen. "Weniger" sollte "weniger" sein. :) – yshavit