web-dev-qa-db-fra.com

Déclaration et initialisation de variables au sein de commutateurs Java

J'ai une question folle sur les commutateurs Java.

int key = 2;

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

Scénario 1 - Lorsque key est égal à deux, la valeur est correctement imprimée sous la forme 2 .
Scénario 2 - Lorsque je vais commenter value = 2 dans case 2:, il se met à hurler en disant que La valeur de la variable locale n'a peut-être pas été initialisée .

Des questions :

Scénario 1: Si le flux d'exécution ne va pas à case 1: (lorsque le key = 2), comment connaît-il le type de la variable de valeur sous la forme int?

Scénario 2: Si le compilateur connaît le type de la variable de valeur comme int, il doit avoir accédé à l'expression int value = 1; dans case 1:. (Déclaration et initialisation). Alors pourquoi fait-il sqawrk Quand je vais commenter value = 2 dans case 2:, en disant le La valeur de la variable locale n’a peut-être pas été initialisée .

89
namalfernandolk

Les instructions de commutateur sont fondamentalement étranges en termes de portée. De section 6.3 de la JLS :

La portée d'une déclaration de variable locale dans un bloc (§14.4) est le reste du bloc dans lequel la déclaration apparaît, commençant par son propre initialiseur et incluant tout déclarant supplémentaire à droite dans l'instruction de déclaration de variable locale.

Dans votre cas, case 2 est dans le même bloc que case 1 et apparaît après, même si case 1 ne s'exécutera jamais ... de sorte que la variable locale est dans la portée et disponible pour écriture malgré logiquement, vous n’exécutez jamais la déclaration. (Une déclaration n'est pas vraiment "exécutable", bien que l'initialisation le soit.)

Si vous commentez l'affectation value = 2;, le compilateur sait toujours à quelle variable vous faites référence, mais vous n'avez pas suivi un chemin d'exécution qui lui attribue une valeur. C'est pourquoi vous obtenez une erreur comme vous le feriez lorsque vous essayez. lire toute autre variable locale non définitivement assignée.

Je vous recommande fortement d'utiliser pas des variables locales déclarées dans d'autres cas - cela conduit à un code très confus, comme vous l'avez vu. Lorsque j'introduis des variables locales dans des instructions switch (ce que j'essaie de faire rarement - les cas doivent être très courts, idéalement), je préfère généralement introduire un nouveau champ d'application:

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

Je crois que c'est plus clair.

106
Jon Skeet

La variable a été déclarée (en tant qu'entier) mais non initialisée (une valeur initiale lui a été attribuée). Pensez à la ligne:

int value = 1;

Comme:

int value;
value = 1;

La partie int value indique au compilateur lors de la compilation que vous avez une variable appelée valeur qui est un int. La partie value = 1 l'initialise, mais cela se produit au moment de l'exécution et ne se produit pas du tout si cette branche du commutateur n'est pas entrée.

21
Paulpro

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

Les déclarations sont traitées à la compilation et ne dépendent pas du flux d'exécution de votre code. Puisque value est déclaré dans le local portée du bloc commutateur, il est utilisable n’importe où dans ce bloc à partir de le point de sa déclaration.

18
Garbage

Avec l’intégration de JEP 325: Expressions de commutateur (Aperçu) dans les versions d’accès anticipé JDK-12. Réponse de Jon

  1. Portée de la variable locale - Les variables locales dans les cas de commutation peuvent désormais être locales à la cas lui-même au lieu du bloc de commutateur entier. Un exemple (similaire à ce que Jon a tenté de faire sur le plan syntaxique) prenant en compte la classe Day enum pour une explication plus détaillée:

    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 Expressions - Si l'intention est d'attribuer une valeur à une variable, puis de l'utiliser, une fois peut utiliser les expressions de commutateur. par exemple.

    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

Cette explication pourrait aider.

    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

Spéc. Java:

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

Le cas d'aboutissement brutal dû à une rupture avec une étiquette est traité par la règle générale pour les instructions étiquetées (§14.7).

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

Déclarations étiquetées:

LabeledStatement: Identifier: Statement

LabeledStatementNoShortIf: Identifiant: StatementNoShortIf

Contrairement à C et C++, le langage de programmation Java n'a pas d'instruction goto; les étiquettes d’instruction d’identifiant sont utilisées avec les instructions break (§14.15) ou continue (§14.16) qui apparaissent n’importe où dans l’étiquette libellée.

L'étendue d'une étiquette d'une instruction étiquetée est l'instruction immédiatement contenue.

En d'autres termes, le cas 1, le cas 2 sont des étiquettes dans l'instruction switch. Les instructions break et continue peuvent être appliquées aux étiquettes.

Etant donné que les étiquettes partagent la portée de l'instruction, toutes les variables définies dans les étiquettes partagent la portée de l'instruction switch.

0
Pavel Molchanov