Java7和Java8中的switch-case语句中不一致的行为

时间:2015-05-26 10:39:12

标签: java switch-statement java-8 java-7

我正在准备Java7 Oracle证书,我想知道为什么Java以如此奇怪的方式处理switch-case:

    public static void main(String[] args) {
    int a = 2;
    switch (a) {
        case 0:
            //System.out.println(b); // cannot find symbol variable b
            break;
        case 1:
            boolean b=false;
            break;
        case 2:
            b = true; // how case knows about existence of variable b?
            break;
        case 3:
            //System.out.println(b); // var b might not have been initialized
            break;
    }
}

为什么案例0和案例3告知未知符号或未初始化变量,这是显而易见的,但我无法想象为什么案例2正常工作?如果在案例1中分配了b,编译器如何知道?对我来说,这不是连贯的。

UPDATE1: 实际上更奇怪的是,在案例3中我注意到编译时错误(Linux64,Java7和Java8),但我的一些同事却没有。

我准备了非常简单的maven项目:https://github.com/gonciarz/switch-test

UPDATE2: 似乎对于每个人来说case3都没有编译。谢谢你们的澄清。

3 个答案:

答案 0 :(得分:4)

您正在混淆声明和作业。在你的代码中

case 1:
    boolean b=false;
    break;
case 2:
    b = true; // how case knows about existence of variable b?
    break;

变量bcase 1:中被声明为声明的范围是switch语句块的其余部分,即最多}

就像你写的那样:

case 1:
    boolean b;// declaration
    b=false;  // assignment
    break;

分配case 2:标签的代码流无效。如果跳转到case 2标签,则变量声明已分配,因为可以跳过赋值但不能声明。

因此行为与您的第三个标签一致:

case 3:
    System.out.println(b); // var b might not have been initialized
    break;

此处,变量b 声明,但未分配。这就是错误消息告诉你的内容:它没有说b未声明,但它“可能没有被初始化”,这包括你肯定知道它没有被初始化的可能性点。

b类型声明的类型,不依赖于任何作业。

作为旁注,switchif之间存在差异。你写过吗

final int a = 2;
boolean b;
if(a == 2) b=false;
System.out.println(b);

a的常量性质导致编译器检测到b将被分配给false并且没有生成错误。这适用于if,但不适用于switch

答案 1 :(得分:1)

这里的范围是整个switch子句,而不是单独的case。范围由{}定义。

当您使用boolean b = false声明变量时,可以在范围的其余部分(即switch子句的其余部分)中访问它。

您在问题中提到的案例3中没有出现错误。

编辑: 你在案例3中得到一个错误,但似乎Eclipse在检测它时很草率。我混淆了字段声明,它获取了具有局部变量的基元的默认值。

答案 2 :(得分:1)

规则说明了这一点:

  

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

和这个

  

声明在编译时处理,不依赖于代码的执行流程。由于value是在switch块的本地范围内声明的,因此从声明的角度来看,它可以在该块中的任何位置使用。