do-while循环的作用范围是什么?

14

在Java中,do-while循环的主体和循环条件不属于同一作用域。因此,以下代码将无法编译:

do {
    boolean b = false;
} while (b); // b cannot be resolved to a variable

但是这段代码对我来说是有意义的。

另外,如果循环体和条件在同一个作用域中,我找不到任何陷阱; 因为循环体总是会被执行,而Java没有Goto语句,所以我不知道外层do-while循环体作用域中的变量声明如何被跳过。 即使可能存在这种情况,编译器也可以检测到并生成编译时错误。

除了保持do-while循环与while循环具有相同的格式之外,还有其他原因吗?我真的很好奇。感谢任何意见!


2
我认为这是因为Java中的作用域是按块{}进行的。 - Bhesh Gurung
1
Java中的作用域由花括号清晰地划分。请注意,while(b)在花括号外部,而布尔变量b在内部。这将它们放置在不同的作用域中。 - DwB
在 Java 中是否可以像在 C/C++ 中一样使用多余的 {} - hugomg
(虽然我要补充的是,如果你使用额外的 {} 来创建块,那么你可能做错了,应该进行重构。) - Dave Newton
8个回答

16

按照您的逻辑,以下情况是在第一次使用之前b未定义的情况:

do {
    continue;
    boolean b = false;
} while (b); // b cannot be resolved to a variable

需要注意的是,布尔型标志通常是代码异味,尽量避免使用它们而不是与它们对抗。


我怀疑这是否是真正的问题?如果这是一个while循环,那么编译器会抱怨“无法访问的代码”,但由于这是一个do-while循环,编译器只会抱怨b未被声明,但我想编译器在单个作用域中也会做同样的事情。谢谢! - zw324
实际问题在于变量的作用域仅限于声明它的 {} 块内。我只是想向您展示,即使不是这种情况,也有可能在未定义 b 的情况下达到 while 条件。 - Tomasz Nurkiewicz
1
如果在if语句的then部分中使用了continue,编译器将无法对“不可达代码”发出警告。 - wannik
1
我讨厌没解释就收到负评。如果我错了,请纠正我,我也想在这里学点东西 :-)。 - Tomasz Nurkiewicz
我喜欢这个例子,给我点赞(+1)。 - Dave Newton
我认为这不是一个很好的例子。如果编译器允许在“do”块中声明的变量出现在“while”块中,那么它将进行控制流分析,就像对每个变量一样,发现“b”在使用时可能未定义,并进行抱怨。这个答案没有给出一个好的理由来解释为什么禁止这种情况意味着类似于“do { int x = something(y); } while (x != 0)”这样的东西也应该被禁止。 - HTNW

10
因为这是Java中定义作用域的一种方式;在 {} 内部是一个新的作用域。
在我看来,对于单个结构进行特殊处理也没有太多意义。

所以除了一般规则之外,没有真正的问题吗?我现在需要研究一下规范:) - zw324
1
@ZiyaoWei 这不是问题,只是不符合你的预期 :) - Dave Newton
2
Java并不总是使用{}来定义作用域。例如,代码“for(int z = 0; z <10; z ++){}”在{}之外定义了z,但其作用域与包含for循环的块不同。我同意OP的观点,即如果Java弯曲了{}作用域规则,使得do-while循环可以终止于不污染外部块命名空间的变量,那么会更好。但现在在Java中进行这种更改已经太晚了。 - Adam Gawne-Cain
@AdamGawne-Cain,这并不改变{}内部是一个新的作用域,特定于OP的问题。话虽如此:for循环变量的作用域被明确地执行为块内的局部变量声明;这些变量声明的作用域与在块内声明它的作用域完全相同(必须如此,因为for循环的语句不能是块语句)。但我会微调措辞。 - Dave Newton

2
在你的例子中,布尔变量b的作用域限定在do..while循环体内。由于条件检查是在循环体外执行的,所以该变量超出了作用域。正确的构造方式应该是:
boolean b = false ; // Or whichever initial value you want
do {
    b = false;
} while (b);

2

如果你想要在do-while循环块内定义布尔值并退出该循环块,可以像这样编写代码:

do{
  boolean b;
  ...
  if(b){
    break;
  }
}while(otherCondition)  //or while(true)

1
do {
    boolean b = false;
}
while (b);

因为布尔变量 b 是一个仅在 内具有作用域的局部变量。

来自 JLS

每个局部变量声明语句都立即包含在一个块中。


0
public class DoWhileLoopExample {

    public static void main(String[] args) {

        int i=1;
        do {
            System.out.println("Do While Loop Example");

        } while(i<1);
    }
}

过度宣传某个特定的产品/资源可能会被社区视为垃圾邮件。请查看帮助中心,特别是用户应该遵守哪些行为准则?的最后一节:避免明显的自我推销。您还可能对如何在Stack Overflow上进行广告宣传?感兴趣。 - Draken

0

这是基本的作用域规则。在一组花括号{}中声明的变量在括号结束时就会超出作用域。它违反了标准作用域规则,而且让编译器检测这种情况需要额外的工作。


0

语句定义和变量在语句块{}之外是不可见的,这就是编译器抱怨的原因。

whiledo ... while的区别在于do ... while保证至少执行一次,并且这是根据JLS更简单的编写方式。

关于变量的作用域,必须按照这些规则进行可见性设置,否则会出现编译时错误。


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