在java开关中声明和初始化变量

8fsztsew  于 2021-06-30  发布在  Java
关注(0)|答案(6)|浏览(378)

我有一个关于java交换机的疯狂问题。

int key = 2;

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

场景1-当 key 如果是2,则成功地将值打印为2。
场景2-我什么时候发表评论 value = 2case 2: 它叫嚷着说局部变量值可能还没有初始化。
问题:
场景1:如果执行流没有转到 case 1: (当 key = 2 ),那么它如何知道值变量的类型 int ?
场景2:如果编译器知道值变量的类型 int ,则它必须访问 int value = 1; 中的表达式 case 1: (声明和初始化)。那为什么我要发表评论的时候它突然变了 value = 2case 2: ,表示局部变量值可能尚未初始化。

mqkwyuun

mqkwyuun1#

基本上,switch语句在作用域方面是奇怪的。根据jls第6.3节:
块中局部变量声明的作用域(§14.4)是出现声明的块的其余部分,从它自己的初始值设定项开始,并在局部变量声明语句的右侧包括任何其他声明符。
就你而言, case 2 在同一个街区 case 1 在它之后出现,尽管 case 1 永远不会执行。。。因此,局部变量在范围内,并且可用于编写,尽管您在逻辑上从未“执行”过声明(声明实际上不是“可执行的”,尽管初始化是。)
如果你把这句话注解掉 value = 2; 赋值时,编译器仍然知道您引用的是哪个变量,但您不会经历任何为其赋值的执行路径,这就是为什么您会像读取任何其他未明确赋值的局部变量时一样出现错误。
我强烈建议您不要使用在其他情况下声明的局部变量—正如您所看到的,这会导致代码非常混乱。当我在switch语句中引入局部变量时(我很少尝试这样做——理想情况下,情况应该很短),我通常更喜欢引入一个新的作用域:

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

我相信这更清楚。

inkz8wg9

inkz8wg92#

在jdk-12早期访问构建中集成了jep325:switch表达式(预览)。从乔恩的回答中可以看出一些变化-
局部变量范围-开关案例中的局部变量现在可以是案例本身的局部变量,而不是整个开关块。一个例子(类似于乔恩在句法上的尝试)考虑到 Day 枚举类以作进一步解释:

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);
    }
}

开关表达式-如果目的是为变量赋值,然后使用它,once可以使用开关表达式。例如

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'
}
ar7v8xwq

ar7v8xwq3#

java规范:
https://docs.oracle.com/javase/specs/jls/se12/html/jls-14.html#jls-14.11
由于标签中断而突然完成的情况由标签语句的一般规则处理(§14.7).
https://docs.oracle.com/javase/specs/jls/se12/html/jls-14.html#jls-14.7
标记语句:
labeledstatement:标识符:语句
labeledstatementnoshortif:标识符:statementnoshortif
与c和c++不同,java编程语言没有goto语句;标识符语句标签与break一起使用(§14.15)或继续(§14.16)出现在标记语句中任何位置的语句。
标签语句的标签范围是立即包含的语句。
换句话说,案例1、案例2是switch语句中的标签。break和continue语句可以应用于标签。
因为标签共享语句的作用域,所以标签中定义的所有变量都共享switch语句的作用域。

yacmzcpb

yacmzcpb4#

从http://www.coderanch.com/t/447381/java-programmer-scjp/certification/variable-initialization-within-case-block
声明是在编译时处理的,不依赖于代码的执行流。自 value 是在开关块的本地范围内声明的,从其声明点开始,它可以在该块的任何位置使用。

tyky79it

tyky79it5#

变量已声明(作为int),但未初始化(已分配初始值)。想想这句台词:

int value = 1;

作为:

int value;
value = 1;

这个 int value 部分在编译时告诉编译器有一个名为value的变量,它是一个int value = 1 part初始化它,但这在运行时发生,如果没有输入开关的分支,则根本不会发生。

aurhwmvo

aurhwmvo6#

这个解释也许有帮助。

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
        }
    }

相关问题