在switch case语句中变量的作用域

107

我觉得我不理解在switch case中作用域是如何工作的。

有人能否向我解释为什么第一段代码无法编译而第二段可以?

代码1:

 int key = 2;
 switch (key) {
 case 1:
      String str = "1";
      return str;
 case 2:
      String str = "2"; // duplicate declaration of "str" according to Eclipse.
      return str;
 }

代码2:

 int key = 2;
 if (key == 1) {
      String str = "1";
      return str;
 } else if (key == 2) {
      String str = "2";
      return str;
 }

变量 "str" 的作用域为什么不包含在 Case 1 内?

如果我跳过声明 Case 1,变量 "str" 就永远没有被声明...


使用 [tag:java-12],对于关于本地变量作用域和 switch 表达式使用的更改,已经回答了原始问题的答案。 - Naman
7个回答

213
我会重复别人说过的:每个case子句中的变量范围对应整个switch语句。但是,你可以使用大括号创建进一步嵌套的作用域,如下所示:
int key = 2;
switch (key) {
case 1: {
    String str = "1";
    return str;
  }
case 2: {
    String str = "2";
    return str;
  }
}

生成的代码现在可以成功编译,因为每个case子句中命名为str的变量都在其自己的作用域内。
还要注意,case:(不带{})的作用域进入“全局”switch作用域。在此之后,每个其他case作用域(带或不带{})都会以一种对于嵌套的Java作用域来说不常见的方式接收这些变量,它们不能被覆盖。因此,例如,仅向第二个case添加{}仍会导致与从第一个case注入的变量相同的错误,但是向第一个case添加大括号将会编译通过。我不确定这是否在规范中定义为这样,但这是大多数实现中发生的情况。

10
听听这个人说的话,他是正确的。 - John
29
正确。但是如果我的团队中的任何程序员没有非常好的理由使用这种“语法”,我会感到非常恼火。它将导致混乱和错误。尽管有return存在,它在视觉上隐藏了第一个case块即使在右花括号之后仍在“继续”,并且容易让人忘记break - leonbloy
3
即使没有必要,为了可维护性和防止错误,请使用“break”语句! - worenga
1
@mightyuhu,break语句不起作用,因为有return语句...至少对于Java来说是这样...C或C++可以... - Boy
2
@Boy 你可能是对的。然而,这并不是我的原始观点。我认为这些过早的返回会导致各种维护和错误伪装问题,更不用说死代码或圆形复杂度了。因此,作为一般建议,在不是微不足道的情况下,应该避免使用这样的结构。 - worenga
显示剩余3条评论

10
变量的作用域是整个switch语句--包括所有的case和default(如果有的话)。

以下是其他一些选项...

选项1:

int key = 2;
switch (key) {
case 1:
     return "1";
case 2:
     return "2";
}

选项2:

int key = 2;
String str = null;
switch (key) {
case 1:
     str = "1";
     return str;
case 2:
     str = "2";
     return str;
}

1
switch (key) { case 1: { String str = "1"; return str; } case 2: { String str = "2"; return str; } }选项3: - Ben Jones

9
你似乎假设每个case都是一个具有自己本地作用域的块,就像if/else块一样。但实际上不是这样的。
纠正这种概念错误非常重要,否则你会经常掉进忘记在case内部使用break的陷阱中。

2

我认为这是一个有效的问题,对于case语句的作用域假设是不可避免的。 我们需要适应它,因为Java编写者已经将其设置为不正确的。

例如,如果语句默认采用其范围内的第一行,那么在使用break语句明确关闭case结尾的情况下,有什么问题呢?因此,在case 1:中声明的内容不应该在case 2中可用,并且它具有并行作用域而不是嵌套作用域。


0
一个 switch 语句可以执行多个 case。所以。。

0

变量的作用域存在于 switch 和 if 语句的大括号之间。在示例代码1中,switch 的大括号包含了变量的两个声明,这会导致编译器出错,因为变量名绑定已经完成。

在另一个示例中,这是可以的,因为两个变量都在自己的大括号(作用域)内声明。


0
在第一个案例中,String声明的范围在switch语句内,因此它被显示为重复项,而在第二个案例中,字符串被包含在花括号中,这限制了它在if/else条件内的范围,因此第二个案例中没有错误。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接