JHa*_*ach 215 java while-loop do-while
我已经用Java编程了好几年了,但我刚刚回到学校获得正式学位.我很惊讶地发现,在我上一次任务中,我使用了如下所示的循环而丢失了分数.
do{
//get some input.
//if the input meets my conditions, break;
//Otherwise ask again.
} while(true)
Run Code Online (Sandbox Code Playgroud)
现在我的测试我只是扫描一些控制台输入,但我被告知这种循环是不鼓励的,因为使用break类似于goto,我们只是不这样做.
我完全理解goto和它的Java堂兄的陷阱break:label,我很有意识不使用它们.我也意识到一个更完整的程序会提供一些其他的逃避手段,例如刚刚结束程序,但这不是我教授引用的原因,所以......
怎么了do-while(true)?
Jon*_*eet 217
我不会说这很糟糕 - 但同样我通常至少会寻找替代方案.
在我写的第一件事情的情况下,我几乎总是至少尝试将它重构为更清晰的东西.有时它无法帮助(或者替代方法是使用一个bool没有任何意义的变量,除了指示循环的结束,不如break声明更清楚),但它至少值得尝试.
作为使用break比标志更清晰的示例,请考虑:
while (true)
{
doStuffNeededAtStartOfLoop();
int input = getSomeInput();
if (testCondition(input))
{
break;
}
actOnInput(input);
}
Run Code Online (Sandbox Code Playgroud)
现在让我们强制它使用一个标志:
boolean running = true;
while (running)
{
doStuffNeededAtStartOfLoop();
int input = getSomeInput();
if (testCondition(input))
{
running = false;
}
else
{
actOnInput(input);
}
}
Run Code Online (Sandbox Code Playgroud)
我认为后者更复杂:它有一个额外的else块,actOnInput更多的缩进,如果你想弄清楚testCondition返回时会发生什么true,你需要仔细查看块的其余部分来检查那里在块之后else不会发生任何事情,无论是否running设置false.
该break声明更清楚地传达了意图,并让其余部分继续了解它需要做的事情,而不必担心早期的情况.
请注意,这与人们对方法中的多个return语句完全相同.例如,如果我可以在前几行中计算出方法的结果(例如,因为某些输入为空,或为空,或者为零),我发现直接返回该答案比使用变量存储结果更清楚,然后整整一块其他代码,最后一个return声明.
El *_*cel 100
AFAIK没什么,真的.老师只是过敏goto,因为他们听到某个地方真的很糟糕.否则你只会写:
bool guard = true;
do
{
getInput();
if (something)
guard = false;
} while (guard)
Run Code Online (Sandbox Code Playgroud)
这几乎是一回事.
也许这更干净(因为所有循环信息都包含在块的顶部):
for (bool endLoop = false; !endLoop;)
{
}
Run Code Online (Sandbox Code Playgroud)
zzz*_*Bov 38
道格拉斯·克罗克福德谈到他希望JavaScript包含一个loop结构:
loop
{
...code...
}
Run Code Online (Sandbox Code Playgroud)
而且我认为Java对于拥有一个loop结构也不会更糟.
没有什么内在的错误的while(true)循环,但就是教师要阻止他们的倾向.从教学的角度来看,让学生创建无限循环并且不理解为什么循环不会被转义是非常容易的.
但他们很少提到的是所有循环机制都可以用while(true)循环复制.
while( a() )
{
fn();
}
Run Code Online (Sandbox Code Playgroud)
是相同的
loop
{
if ( !a() ) break;
fn();
}
Run Code Online (Sandbox Code Playgroud)
和
do
{
fn();
} while( a() );
Run Code Online (Sandbox Code Playgroud)
是相同的:
loop
{
fn();
if ( !a() ) break;
}
Run Code Online (Sandbox Code Playgroud)
和
for ( a(); b(); c() )
{
fn();
}
Run Code Online (Sandbox Code Playgroud)
是相同的:
a();
loop
{
if ( !b() ) break;
fn();
c();
}
Run Code Online (Sandbox Code Playgroud)
只要你可以设置你的循环中,一个方式工作,你选择使用结构是不重要的.如果恰好适合for循环,请使用for循环.
最后一部分:保持循环简单.如果每次迭代都需要执行许多功能,请将其放在函数中.您可以在工作完成后随时对其进行优化.
Jes*_*own 15
早在1967年,Dijkstra在一本贸易杂志上写了一篇关于为什么要从高级语言中删除goto以提高代码质量的文章.一个称为"结构化编程"的整个编程范例就是出于此,但当然并不是每个人都认为goto自动意味着代码不好.结构化编程的关键在于,代码的结构应该尽可能地确定其流程,而不是让步或者中断或继续确定流程.同样,在该范例中也不鼓励在循环或函数中具有多个进入和退出点.显然,这不是唯一的编程范例,但通常它可以很容易地应用于其他范例,如面向对象编程(ala Java).您的老师可能已经被教过,并且正在努力教您的课程,我们最好通过确保我们的代码结构化,并遵循结构化编程的隐含规则来避免"意大利面条代码".虽然使用break的实现没有任何固有的"错误",但是有些人认为在while()条件中明确指定循环条件的情况下读取代码要容易得多,并且消除了一些过于棘手的可能性.使用一段时间(真实)条件肯定存在陷阱,这些条件似乎是新手程序员经常在代码中弹出的,例如意外创建无限循环的风险,或者使代码难以阅读或不必要的混淆.
具有讽刺意味的是,异常处理是一个区域,当您进一步使用Java编程时,结构化编程的偏差肯定会出现并且可以预期.
您的教师也可能希望您能够证明您能够使用特定的循环结构或在该章或教科书中教授的语法,并且您编写的代码在功能上等同,您可能没有证明你应该在那一课中学到的特殊技能.
Ken*_*oom 14
用于读取输入的用户Java惯例是:
import java.io.*;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String strLine;
while ((strLine = br.readLine()) != null) {
// do something with the line
}
Run Code Online (Sandbox Code Playgroud)
通常用于读取输入的C++约定是:
#include <iostream>
#include <string>
std::string data;
while(std::readline(std::cin, data)) {
// do something with the line
}
Run Code Online (Sandbox Code Playgroud)
在C中,它是
#include <stdio.h>
char* buffer = NULL;
size_t buffer_size;
size_t size_read;
while( (size_read = getline(&buffer, &buffer_size, stdin)) != -1 ){
// do something with the line
}
free(buffer);
Run Code Online (Sandbox Code Playgroud)
或者,如果您确信您知道文件中最长的文本行有多长,那么您可以这样做
#include <stdio.h>
char buffer[BUF_SIZE];
while (fgets(buffer, BUF_SIZE, stdin)) {
//do something with the line
}
Run Code Online (Sandbox Code Playgroud)
如果您正在测试用户是否输入了quit命令,则可以轻松扩展这3个循环结构中的任何一个.我会用Java为你做的:
import java.io.*;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = br.readLine()) != null && !line.equals("quit") ) {
// do something with the line
}
Run Code Online (Sandbox Code Playgroud)
所以,虽然确实存在某种情况break或者说goto是合理的,但如果您所做的只是逐行读取文件或控制台,那么您不需要while (true)循环来完成它 - 您的编程语言已经为您提供了使用输入命令作为循环条件的适当习惯用法.
rfe*_*eak 12
这不是一件很糟糕的事情,但在编码时你需要考虑其他开发人员.即使在学校.
你的开发人员应该能够在循环声明中看到你的循环的exit子句.你没有这样做.你在循环中间隐藏了退出子句,为其他人提供了更多的工作并试图理解你的代码.这与避免像"休息"这样的事情是一样的.
话虽这么说,你仍然可以在现实世界中看到很多代码.
jqa*_*jqa 11
这是你的枪,你的子弹和你的脚......
这很糟糕,因为你在寻找麻烦.本页面上的您或任何其他海报都不会有短/简单的循环示例.
麻烦将在未来的某个非常随机的时间开始.它可能是由另一个程序员引起的.可能是安装软件的人.它可能是最终用户.
为什么?我必须找出为什么700K LOC应用程序会逐渐开始燃烧100%的CPU时间,直到每个CPU都饱和为止.这是一个惊人的while(真)循环.这是大而令人讨厌但它归结为:
x = read_value_from_database()
while (true)
if (x == 1)
...
break;
else if (x ==2)
...
break;
and lots more else if conditions
}
Run Code Online (Sandbox Code Playgroud)
没有最终的其他分支.如果该值与if条件不匹配,则循环一直运行直到时间结束.
当然,程序员指责最终用户没有选择程序员所期望的价值.(然后我在代码中删除了while(true)的所有实例.)
恕我直言,使用像while(true)这样的结构并不是一个好的防御性编程.它会回来困扰你.
(但我确实记得,如果我们不评论每一行,即使对于i ++,教授们也会评分;)
从某种意义上讲,结构化编程构造比(有点非结构化的)break和continue语句更受欢迎.相比之下,它们优选根据该原理"转到".
我总是建议尽可能让你的代码尽可能结构化......但是,正如Jon Skeet指出的那样,不要让它比那更有条理!
根据我的经验,在大多数情况下,循环具有继续运行的“主要”条件。这是应该写入while()运算符本身的条件。所有其他可能破坏循环的条件都是次要的,不是那么重要,等等。它们可以写为其他if() {break}语句。
while(true) 常常令人困惑并且可读性较差。
我认为这些规则并未涵盖100%的案件,但可能只涵盖其中的98%。
| 归档时间: |
|
| 查看次数: |
160014 次 |
| 最近记录: |