在Java交换机中声明和初始化变量

时间:2012-05-30 06:04:53

标签: java scope initialization switch-statement declaration

我有一个关于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 = 2中评论case 2:时,它会发出声音,说明本地变量值可能尚未初始化

问题:

场景1:如果执行流程没有转到case 1:(当key = 2时),那么它如何知道值变量的类型为{{1 }}?

场景2:如果编译器知道值变量的类型为int,那么它必须访问int中的int value = 1;表达式。(声明和初始化)。那么为什么sqawrk当我要在case 1:中评论value = 2时,说本地变量值可能尚未初始化

6 个答案:

答案 0 :(得分:108)

切换语句在范围方面基本上是奇怪的。来自section 6.3 of the JLS

  

块中的局部变量声明的范围(第14.4节)是声明出现的块的其余部分,从其自己的初始化器开始,并包括局部变量声明语句中右侧的任何其他声明符。 / p>

在您的情况下,case 2case 1位于同一中并显示在其后面,即使case 1永远不会执行...所以尽管您在逻辑上从不“执行”声明,但本地变量在范围内且可用于写入。 (尽管初始化是,但声明并不是真正的“可执行”。)

如果您注释掉value = 2;赋值,编译器仍然知道您指的是哪个变量,但是您不会通过任何为其赋值的执行路径,这就是为什么你得到一个您尝试读取任何其他未明确分配的局部变量时的错误。

我强烈建议你使用在其他情况下声明的局部变量 - 它会导致代码高度混乱,正如您所见。当我在switch语句中引入局部变量时(我很少尝试这样做 - 案例应该很短,理想情况)我通常更喜欢引入一个新的范围:

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

我相信这更清楚。

答案 1 :(得分:21)

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

int value = 1;

如:

int value;
value = 1;

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

答案 2 :(得分:18)

来自http://www.coderanch.com/t/447381/java-programmer-SCJP/certification/variable-initialization-within-case-block

  

声明在编译时处理,不依赖于   代码的执行流程。由于value是在本地声明的   切换块的范围,它可以在该块的任何地方使用   宣言的重点。

答案 3 :(得分:2)

在JDK-12中集成了JEP 325: Switch Expressions (Preview)的早期访问版本。从Jon's answer-

可以看到某些变化
  1. 局部变量作用域 -开关盒中的局部变量现在可以是盒本身的局部而不是整个开关块。考虑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);
        }
    }
    
  2. 开关表达式 -如果要为变量赋值然后再使用它,一次可以使用开关表达式。例如

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

答案 4 :(得分:0)

此说明可能会有所帮助。

{{1}}

答案 5 :(得分:0)

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)或Continue一起使用   (§14.16)语句出现在带标签的语句中的任何地方。

     

带标签的语句的标签范围是立即   包含的声明。

换句话说,情况1,情况2是switch语句中的标签。 break和continue语句可以应用于标签。

因为标签共享语句的范围,所以标签内定义的所有变量都共享switch语句的范围。