这个while循环有什么问题?

7
boolean r = false ; int s = 0 ;
while (r == false) ; 
{
    s = getInt() ; 
    if (!(s>=0 && s<=2)) System.out.println ("try again not a valid response") ; 
    else r = true ; 
}

文本永远不会显示,即使输入3或123,循环也永远不会终止。这里有什么问题?

此外,这不是一个无限循环,因此“infinite-loop”标签没有意义。 - Daniel DiPaolo
3
实际上,这是一个无限循环。while (r == false) 是一个无限循环,不做任何事情,因为 r 被初始化为 false。 - Dave Costa
7
停止尝试将多个内容放在同一行,这往往是导致问题的主要原因。当你养成清晰写作的习惯后,这种情况会减少。此外,请将Eclipse中的警告设置得更高,它会指出空语句的错误。不仅要解决当前问题,还要修复根本原因。 - Bill K
糟糕!我竟然发表了被接受的答案,然后第二次错误地读错代码,并且因为认为它是while(false)而自食其言。 - Daniel DiPaolo
2
啊啊啊啊啊!我的眼睛!!!请考虑在if语句中添加一些缩进。即使是最简单的控制语句,在没有缩进和开/闭括号的情况下把所有内容堆积在一行中,也会变得难以阅读。此外,请重构if语句中的表达式,以便不使用否定(!)。很少有情况需要使用复合布尔表达式的否定形式。 - luis.espinal
1
要找出问题,直接在调试器中逐步跟踪代码不是更简单吗? - Kevin
7个回答

34

在条件之后你使用了分号。 当你使用大括号为while指定一个块时,不要使用分号。


5
呵呵……while (r==false) /*什么都不做*/ ; - Armstrongest

9

请删除 while 后面的 ';'。


8

其他人已经指出了这个漏洞,但你的代码在其他方面也很可怕,最终会让你失误:

if (!(s>=0 && s<=2)) System.out.println ("try again not a valid response") ; 
else r = true ; 

这是不好的,因为在ifelse语句中,您很容易意图运行多个语句。使用花括号并避免将条件语句放在一行上:

if (!(s>=0 && s<=2))
{
    System.out.println ("try again not a valid response");
}
else
{
    r = true;
}

更易于阅读且不太可能引入难以发现的错误。

2
我不同意使用花括号。如果只有一条语句,那就只有一条语句。作为一种风格,我会缩进但不使用花括号来表示单个语句...然而这是一场信仰之争。 - Armstrongest
2
@Atomiton 绝对的,我喜欢一直使用它们,因为我很可能会在某个时候回来并进行更改,如果我一开始没有将它们放在那里,那么我就会出错。至少将它们放在不同的行上 - 我希望我们可以达成共识 :) - Jonathon Faust
我从不为单个语句使用花括号,而且我经常回来添加更多内容,我从未意外忘记添加花括号并搞乱了控制流程...除非我已经写了一段时间的Python然后回到C。 - Carson Myers
5
虽然我经常在单行语句中省略花括号,但我不能为这种做法辩护。事实上,即使有花括号,成本几乎为零,即使它们有时会让你感到困惑,重新看一眼也只需要不到一秒钟的时间。另一方面,如果省略花括号——比如在一千个“if”语句中甚至只有一次(比方说当你写了一段时间的Python后回到C)——如果你偶然搞错了,可能需要几分钟或几小时才能修复,这是不可接受的,而且显然是错误的。尽管如此,我仍然更多地省略它们…… - Bill K
3
我喜欢当别人说:“我再也不会犯那个错误了。” 因为回来修改代码的可能并不是你,而且写出来的代码可能已经过了几个月,就好像它是由其他人编写的一样。 - Paul McKenzie
显示剩余2条评论

3

+1 给 Daniel DiPaolo。我想发一篇单独的回答来澄清这个问题。

在 Java 中,while 循环可以用两种方式编写。如果循环体只有一行代码,可以使用简写形式:

while (true)
    System.out.println("While loop");

这将在控制台上打印出"while循环",直到程序结束。另一个选项是在大括号之间指定循环体,就像你上面所做的那样:
int i = 0;
while (i < 10) {
    System.out.println("i = " + i);
    i++;
}

这将在单独的行上打印出“i = 0”,“i = 1”等,“i = 9”。
你发布的代码所做的是混淆了两者。在简写的while循环中,Java解析器希望在while循环条件和分号之间找到一个语句。由于它在这里找不到语句,所以while循环运行,但什么也没有做;它没有主体。此外,由于循环没有主体,您的变量r无法有机会假定新值;条件始终计算为true,循环永远不会退出。
如果您在示例中的while循环中否定条件,即:
boolean r = false ; int s = 0 ;
while (r != false) ; 
{
    s = getInt() ; 
    if (!(s>=0 && s<=2)) System.out.println ("try again not a valid response") ; 
    else r = true ; 
}

(请注意,我在这里留下了错误的分号),你会发现你想要执行的循环体只会被执行一次,因为循环永远不会运行。


3
除了其他评论之外,您还应该将if更改为
if (s < 0 || s > 2)

这样更易理解。


+1 绝对的,否定使得本应简单易读的内容变得繁琐。 - Jonathon Faust

3

当(r == false)时

应该为

while(!r)

尽管其他人都说分号是问题所在,但我认为这才是它的问题 :)


1
while(r == false) 更加明确和易读。我想人们也可以争辩说应该是 while(false == r),但我讨厌那样做。无论如何,他不必改变它为 !r,因为 r 是一个布尔值,所以无论哪种方式都没有关系,这只是一个风格问题。 - Carson Myers
一贯地遵循约定的 r!r,而不是 r == falser == true,可以避免在 Java 中出现 r = falser = true 的错误(这不会导致编译错误)。如果您想使其更明确和易读,请将 r 重命名为类似于 continuefound 的内容。 - ILMTitan
1
continue是一个关键字,所以它不适合作为变量名。你说得对,像r和s这样的变量名也很糟糕。使用现代IDE自动补全功能,并将其命名为一些有意义的名称,比如done或found。 - ajs410
1
@Myers 我不同意。我认为 r == false 是代码异味,我永远不想看到有人在我正在使用的代码中使用它。 - John Vint

1

不相关的回答,我真的非常建议你遵循Sun的样式指南。

boolean r = false ; 
int s = 0 ;
while (r == false) {
    s = getInt() ; 
    if (!(s>=0 && s<=2)) {
        System.out.println ("try again not a valid response") ; 
    } else {
      r = true ;
    } 
}

如果你在循环中评估结果,就可以摆脱r变量和if/else条件。

int s = 0;

while( ( s = getInt() ) < 0 || s > 2 ) {
    System.out.println( "Try again, not a valid response");
}

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