Seit Java 1.7 können Strings mit switch-Anweisungen verwendet werden, was mich etwas beunruhigt. switch
Anweisungen auf Integer-Werte in Sprungtabellen umgewandelt werden, die schneller sind als einfach if
prüft auf Ganzzahlen berechnet zur Laufzeit; Kann eine ähnliche Optimierung mit Strings durchgeführt werden oder ist dies nur syntaktischer Zucker?Ist Switch mit Strings mehr als nur syntaktischer Zucker?
Antwort
Yes Schalter mit Schnur ist ein syntatic Zucker. Von here
1) Strings in Switch sind syntaktischer Zucker, keine Änderung der JVM-Ebene.
2) Intern verwendet es equals-Methode zu vergleichen, das heißt, wenn Sie übergeben Null wird es werfen java.lang.NullPointerException, also Vorsicht vor dass.
3) Bei Strings in Switch-Anweisungen wird zwischen Groß- und Kleinschreibung unterschieden, vorzugsweise wird nur ein Fall verwendet und die Eingabe in den bevorzugten Fall konvertiert, bevor sie an switch statement übergeben wird.
Überprüfen Sie auch How String in Switch works in Java 7
Aus dem gleichen Link, wenn Sie das Beispiel sehen:
public class StringInSwitchCase{
public static void main(String[] args) {
String mode = args[0]; switch (mode) {
case "ACTIVE": System.out.println("Application is running on Active mode");
break;
case "PASSIVE": System.out.println("Application is running on Passive mode");
break;
case "SAFE": System.out.println("Application is running on Safe mode");
} } }
und den dekompilierten Code:
import java.io.PrintStream;
public class StringInSwitchCase{
public StringInSwitchCase() { }
public static void main(string args[]) {
String mode = args[0]; String s;
switch ((s = mode).hashCode()) {
default: break;
case -74056953: if (s.equals("PASSIVE")) {
System.out.println("Application is running on Passive mode"); }
break;
case 2537357: if (s.equals("SAFE")) { System.out.println("Application is running on Safe mode"); }
break;
case 1925346054: if (s.equals("ACTIVE")) { System.out.println("Application is running on Active mode"); }
break; } } }
werden Sie feststellen, dass String in Switch funktioniert mit hashCode()
und equals()
Methode.
Wie erwartet verwendet es hashCode() Methode zum Schalten und equals() Verfahren zur Verifikation bedeutet dies, es ist nur ein syntaktischer Zucker, anstatt eine eingebaute nativen Funktionalität.
Die letzten beiden Aussagen dort treffen mich als widersprüchlich: ist der Unterschied in der Byte-Code-Effizienz wirklich so groß, wenn es erfordert, dass Sie eine neue, niedrigere/erstellen Großbuchstaben, um es zu benutzen? –
Also ... wenn der Byte-Code effizienter ist, dann sind sie nicht genau syntaktischer Zucker. – RealSkeptic
@JeroenVannevel: - Ja das ist widersprüchlich. Ich habe diesen Teil entfernt und den Code hinzugefügt, um ihn klarer zu machen. –
Der Compiler optimiert eine switch
Anweisung basierend auf String-Werte der hashCode()
Methode verwenden, und verwendet dann eine Lookup-Tabelle im Bytecode. Dies ist im Allgemeinen effizienter als eine if
- else
Anweisung.
Zum Beispiel die folgenden:
String string = "x";
switch(string) {
case "x": System.out.println("x");
break;
case "y": System.out.println("y");
break;
case "z": System.out.println("z");
break;
}
ist diesem Bytecode umgewandelt:
ldc "x"
astore_1
aload_1
astore_2
iconst_m1
istore_3
aload_2
invokevirtual java/lang/String/hashCode()I
tableswitch 120
10
17
24
default: 30
aload_2
ldc "x"
invokevirtual java/lang/String/equals(Ljava/lang/Object;)Z
ifeq 30
iconst_0
istore_3
goto 30
aload_2
ldc "y"
invokevirtual java/lang/String/equals(Ljava/lang/Object;)Z
ifeq 30
iconst_1
istore_3
goto 30
aload_2
ldc "z"
invokevirtual java/lang/String/equals(Ljava/lang/Object;)Z
ifeq 30
iconst_2
istore_3
iload_3
tableswitch 0
32
36
40
default: 43
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "x"
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
goto 43
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "y"
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
goto 43
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "z"
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
return
Warum wäre das effizienter? Ein Einschalten von im Wesentlichen zufälligen Schlüsseln kann keine Sprungtabelle verwenden. Die Sprungtabelle würde im schlimmsten Fall 2^32 Einträge benötigen. – usr
@ usr Auch wenn eine Jump-Tabelle nicht verwendet werden kann, selbst wenn der Switch eine Reihe von if-else-Prüfungen für einen Integer-Wert beendet, ist dies immer noch weniger teuer als eine Reihe von if-else-Prüfungen für einen String-Wert. – hvd
'String' Schalter scheint eine feste Größe Karte implementiert werden unter Verwendung von in der logarithmischen Leistung führt für eine kleine Anzahl von Artikel. Siehe http://java-performance.info/string-switch-performance/ – isnot2bad