webentwicklung-frage-antwort-db.com.de

Variablen innerhalb von Java-Switches deklarieren und initialisieren

Ich habe eine verrückte Frage zu Java-Switches.

int key = 2;

switch (key) {
    case 1:
        int value = 1;
        break;
    case 2:
        value = 2;
        System.out.println(value);
        break;
    default:
        break;
}

Szenario 1 - Wenn key zwei ist, wird der Wert erfolgreich als 2 ..__ gedruckt.
Szenario 2 - Wenn ich value = 2 in case 2: kommentieren werde, kreischt es mit den Worten . Der Wert der lokalen Variablen wurde möglicherweise nicht initialisiert.

Fragen :

Szenario 1: Wenn der Ausführungsablauf nicht zu case 1: (wenn key = 2) geht, woher weiß der Typ der Wertvariablen als int?.

Szenario 2: Wenn der Compiler den Typ der Wertvariablen als int kennt, muss er auf den Ausdruck int value = 1; in case 1: (Deklaration und Initialisierung) zugegriffen haben. Dann warum squrrk Wenn ich value = 2 in case 2: kommentieren und sagen möchte, dass Der Wert der lokalen Variablen nicht initialisiert wurde.

89
namalfernandolk

Switch-Aussagen sind im Wesentlichen in Bezug auf den Umfang ungerade. Aus Abschnitt 6.3 der JLS :

Der Geltungsbereich einer Deklaration einer lokalen Variablen in einem Block (§ 14.4) ist der Rest des Blocks, in dem die Deklaration auftritt, beginnend mit einem eigenen Initialisierer und der Einfügung weiterer Deklaratoren rechts in der Deklaration der lokalen Variablen.

In Ihrem Fall befindet sich case 2 im selben block wie case 1 und erscheint danach, obwohl case 1 niemals ausgeführt wird ... daher ist die lokale Variable im Gültigkeitsbereich und steht für writing zur Verfügung, obwohl Sie logischerweise niemals " Ausführen der Deklaration. (Eine Deklaration ist nicht wirklich "ausführbar", obwohl die Initialisierung ist.)

Wenn Sie die value = 2;-Zuweisung auskommentieren, weiß der Compiler immer noch, auf welche Variable Sie sich beziehen, aber Sie haben keinen Ausführungspfad durchlaufen, der ihm einen Wert zuweist. Deshalb erhalten Sie eine Fehlermeldung, wie Sie es beim Versuch tun würden um andere, nicht definitiv zugewiesene lokale Variablen zu lesen.

Ich würde Ihnen dringend empfehlen, not zu verwenden, um lokale Variablen zu verwenden, die in anderen Fällen deklariert wurden. Dies führt zu sehr verwirrendem Code, wie Sie gesehen haben. Wenn ich lokale Variablen in switch-Anweisungen einführe (was ich selten versuche - die Fälle sollten im Idealfall sehr kurz sein), ziehe ich normalerweise einen neuen Geltungsbereich vor:

case 1: {
    int value = 1;
    ...
    break;
}
case 2: {
    int value = 2;
    ...
    break;
}

Ich glaube das ist klarer.

106
Jon Skeet

Die Variable wurde deklariert (als int), aber nicht initialisiert (mit einem Anfangswert zugewiesen). Denken Sie an die Linie:

int value = 1;

Wie:

int value;
value = 1;

Der int value-Teil teilt dem Compiler zur Kompilierzeit mit, dass Sie eine Variable namens value haben, die ein int ist. Der value = 1-Teil initialisiert ihn, dies geschieht jedoch zur Laufzeit und tritt überhaupt nicht auf, wenn der Zweig des Switches nicht eingegeben wird.

21
Paulpro

Von http://www.coderanch.com/t/447381/Java-programmer-SCJP/certification/variable-initialization-within-case-block

Deklarationen werden zur Kompilierzeit verarbeitet und hängen nicht von der .__ ab. Ausführungsfluss Ihres Codes. Da value innerhalb der lokalen .__ deklariert ist. Im Rahmen des Schalterblocks ist er überall in diesem Block von .__ aus verwendbar. der Punkt seiner Erklärung.

18
Garbage

Mit der Integration von JEP 325: Switch Expressions (Preview) in JDK-12 baut Early Access auf. Es gibt bestimmte Änderungen, die man an Jons Antwort sehen kann

  1. Local Variable Scope - Die lokalen Variablen in den Switch-Fällen können jetzt lokal zum Case selbst anstelle des gesamten Switch-Blocks sein. Ein Beispiel (ähnlich dem, was Jon auch syntaktisch versucht hatte), wobei die Day-Enum-Klasse zur weiteren Erklärung betrachtet wird:

    public enum Day {
        MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
    }
    
    // some another method implementation
    Day day = Day.valueOf(scanner.next());
    switch (day) {
        case MONDAY,TUESDAY -> {
            var temp = "mon-tue";
            System.out.println(temp);
        }
        case WEDNESDAY,THURSDAY -> {
            var temp = Date.from(Instant.now()); // same variable name 'temp'
            System.out.println(temp);
        }
        default ->{
            var temp = 0.04; // different types as well (not mandatory ofcourse)
            System.out.println(temp);
        }
    }
    
  2. Switch-Ausdrücke - Wenn beabsichtigt ist, einer Variablen einen Wert zuzuweisen und diesen dann zu verwenden, können einmal die Switch-Ausdrücke verwendet werden. z.B.

    private static void useSwitchExpression() {
        int key = 2;
        int value = switch (key) {
            case 1 ->  1;
            case 2 -> 2;
            default -> {break 0;}
        };
        System.out.println("value = " + value); // prints 'value = 2'
    }
    
1
nullpointer

Diese Erklärung kann hilfreich sein.

    int id=1;

    switch(id){
        default: 
            boolean b= false; // all switch scope going down, because there is no scope tag

        case 1:
            b = false;
        case 2:{
            //String b= "test"; you can't declare scope here. because it's in the scope @top
            b=true; // b is still accessible
        }
        case 3:{
            boolean c= true; // case c scope only
            b=true; // case 3 scope is whole switch
        }
        case 4:{
            boolean c= false; // case 4 scope only
        }
    }
0
Java jansen

Java-Spezifikation:

https://docs.Oracle.com/javase/specs/jls/se12/html/jls-14.html#jls-14.11

Für den Fall einer abrupten Fertigstellung aufgrund eines Abbruchs mit einem Label gilt die allgemeine Regel für Label-Anweisungen (§14.7).

https://docs.Oracle.com/javase/specs/jls/se12/html/jls-14.html#jls-14.7

Beschriftete Aussagen:

LabeledStatement: Identifier: Anweisung

LabeledStatementNoShortIf: Bezeichner: StatementNoShortIf

Im Gegensatz zu C und C++ hat die Programmiersprache Java keine goto-Anweisung. Bezeichneranweisungsbezeichnungen werden mit break-Anweisungen (§14.15) oder continue-Anweisungen (§14.16) verwendet, die an einer beliebigen Stelle in der beschrifteten Anweisung erscheinen.

Der Geltungsbereich einer Kennzeichnung einer gekennzeichneten Aussage ist die unmittelbar enthaltene Aussage.

Mit anderen Worten, Fall 1, Fall 2 sind Bezeichnungen innerhalb der switch-Anweisung. break- und continue-Anweisungen können auf Labels angewendet werden.

Da Labels den Gültigkeitsbereich der Anweisung teilen, teilen sich alle in Labels definierten Variablen den Gültigkeitsbereich der switch-Anweisung.

0
Pavel Molchanov