为什么这个循环不好练习?

时间:2014-01-13 16:26:53

标签: java loops coding-style

以下循环不是好习惯。是因为Stringfor循环的主要条件而不是int变量,这意味着for循环是无限的?另外,是否由于没有实例进入'结束'来停止循环?

Scanner in = new Scanner(System.in);
int i = 0;
for (String s = in.next(); !s.equals("end"); i++) 
{
    System.out.println("The value of i is: " + i + " and you entered " + s);
}

如何重写它,使其符合公认的风格?

(这是过去试卷中的一个问题。)

17 个答案:

答案 0 :(得分:39)

你的字符串s永远不会改变,这会导致无限循环。你可能想要:

for (String s = in.next(); !s.equals("end"); s = in.next(), i++) {
    ...
}

有些人(包括我)可能会说i++不应该在此循环的增量部分,因为它与条件没有直接关系:

for (String s = in.next(); !s.equals("end"); s = in.next()) {
    ...
    i++;
}

  

是否由于字符串是for循环的主要条件而不是int变量,这意味着for循环是无限的?

原始循环确实是无限的(至少在输入初始输入并假设"end"不是第一个输入之后)。但是,这并不是你说的原因。 For循环 最常用整数循环控制变量编写,但情况并非总是如此。例如,迭代链表的常用习语是:

for (Node node = list.head; node != null; node = node.next) {
    ...
}

你的循环问题是字符串s永远不会改变,所以它永远不会等于"end",除非那是第一个输入。

答案 1 :(得分:34)

我建议将循环条件和对Scannner.next()的调用分开:

while (in.hasNext()) {
    String s = in.next();
    if (s.equals("end")) {
      break;
    }
    System.out.println("The value of i is: " + i + " and you entered " + s);
    i++;
}

我认为这比试图将所有内容都压缩到for表达式更容易理解。

答案 2 :(得分:6)

此代码存在多个问题:

  1. s在初始分配后永远不会改变,因此它是一个无限循环。
  2. 致电.next()可能会抛出NoSuchElementExceptionIllegalStateException。我认为事先检查.hasNext()更为礼貌,而不是捕获这些例外,因为输入的输出是可预见的而不是特殊的情况。但是,替代请求宽恕方式也是可以接受的。
  3. for-loop标题不会形成连贯的故事 - 它会初始化s并测试s,但会更新i
  4. 在我看来,System.out.format()会更加优于System.out.println()连接。
  5. 我会把它写成:

    Scanner in = new Scanner(System.in);
    int i = 0;
    String s;
    while (in.hasNext() && !"end".equals(s = in.next())) {
        System.out.format("The value of i is: %d and you entered %s\n", i++, s);
    }
    

    它可能是一个很好的用户界面触摸,告诉用户end是一个神奇的词来终止循环(假设它被修改为可能的工作)。

答案 3 :(得分:4)

for循环的常见做法是在每个术语中重复计数器变量:

for(int i=...; i<... ; i++)

在上面的示例中,代码混合了变量。这让读者感到困惑,并且如果输入end作为第一个值,可能会导致循环仅终止的错误。

答案 4 :(得分:2)

这个循环是一个坏主意,因为你从用户输入而不是每次迭代都设置s一次。 因此,如果s填充了与“结束”不同的值,它将导致您无限时间运行。

你可能想要更像这样的东西:

for (String s; (s = in.nextLine()).equals("end"); i++) 
{
    System.out.println("The value of i is: " + i + " and you entered " + s);
}

答案 5 :(得分:2)

这不是一个好主意,因为字符串s可能永远不会等于"end"。您可能想要检查扫描仪是否有另一个字符串。此外,您只需将字符串初始化为in.next(),但您需要在循环的每次迭代后将s设置为下一个字符串。

while(in.hasNext()) {
  String s = in.next();
  if (s.equals("end")) {
    break;
  }
  // ..
}

答案 6 :(得分:2)

这种方法太糟糕了。

给定代码: -

Scanner in = new Scanner(System.in);
int i = 0;
for (String s = in.next(); !s.equals("end"); i++) 
{
    System.out.println("The value of i is: " + i + " and you entered " + s);
}

for循环的第一部分仅在生命中执行一次。

String s = in.next() //Execute only once in life

这个for循环的第二部分永远不会成立,因为输入控制台永远不会允许输入第二个输入。

!s.equals("end")//2nd part

此程序永远不允许从控制台输入第二个输入,因为in.next()只执行一次。此循环的退出标记为“结束”,在首次输入后无法输入。

这种类型的循环应该通过while循环来实现。

Scanner in = new Scanner(System.in);
while(in.hasNext()){
String yourdata=in.next();
if(yourdata.equals("end")){
//Stop the loop 
}
//Do you code here
}

答案 7 :(得分:1)

字符串s永远不会被修改。循环永远不会结束。那怎么样:

    Scanner in = new Scanner(System.in);
    String s = "";
    for (int i = 0 ; !s.equals("end"); i++) {
        s = in.next();
        System.out.println("The value of i is: " + i + " and you entered "
                + s);
    }

答案 8 :(得分:1)

我刚刚发表评论,但我还没有代表。 我没有看到的解释是为什么你的价值不会改变。

在典型的 for 循环中:

for(a=1; a<=10; a+=1) {body}

初始短语“a = 1”仅作为初始化执行一次。

第三个短语'a + = 1',在每个周期结束时执行一次,直到......

第二个短语'a&gt; = 10',评估为false。

所以 for 循环会在'psuedo-code'中表示如下:

    a=1         // first phrase
:LoopLabel
    {body}
    a+=1        // third phrase
    if (a<=10)  // second phrase (boolean evaluation)
        then goto LoopLabel

同样,您的示例在类似的伪代码中可能如下所示:

    Scanner in = new Scanner(System.in);
    int i = 0;
    String s = in.next()
:LoopLabel
    {
        System.out.println("The value of i is: " + i + " and you entered " + s);
    }
    ++i
    if (!s.equals("end"))
        goto LoopLabel

所以你的程序是一个无限循环的原因是's'的值只在进入你的循环时设置,并且在每次循环执行期间都没有改变,这是最有可能的。

答案 9 :(得分:1)

由于两件事情,这不是一个好的做法:

  1. for循环意味着迭代数据集合
  2. for循环包含迭代器初始状态,循环条件和相关的迭代函数
  3. for语句只混合了两个不同的信息(流和计数器)。即使确实有效,也不好的做法。

答案 10 :(得分:1)

我认为这是不好的做法,因为不需要for循环。在这种情况下,我认为它没用。可能就是这样:

Scanner in = new Scanner(System.in);
String s = in.next();
if (!s.equals("end"))
{
    System.out.println("You have enetered" + s);
}

看,没有任何需要循环。你所拥有的循环使事情变得比以往更加复杂。除非他们需要复杂性,否则我总是认为事情应该尽可能简单。只有在您希望代码执行多个操作时才会使用For个循环。在上面的例子中,只发生了一件事:println语句,因此不需要循环。这是不必要的......

此外,循环永远不会结束。所以也是这样,但那只是错误的代码。这不是为什么这是不好的做法。由于不必要地使用for循环,这是不好的做法。这也是错误的,因为代码是错误的。所以这段代码有两个不同的事情。

答案 11 :(得分:1)

其他人提到循环没有结束,因为你没有改变s的值,所以循环永远不会结束。这可能是你教授的意图,也可能不是。糟糕的做法通常是不好的做法,但还有其他原因导致这种做法不好。

在我这里做的不好的做法,以及教授本来想要的是在这里使用for循环。正如我的教授告诉我的那样,“For循环用于何时知道何时需要代码结束,而循环用于何时您不知道何时希望代码结束。”因此,如果您有一个可迭代的i,例如此代码:

for(i = 0; i<100; i++)
{
    ...
}

在此代码中,您知道要将i从0迭代到100.在您的教授讨论的情况下,您希望使用while循环。

int counter;
while(*(str+counter))
    counter++;

你不知道循环什么时候结束,因为你不知道str有多长,但你知道有时它会到达空指针,循环将终止。这通常是什么是最佳做法。

因此,对于您的教授发布的代码,您可能希望它看起来像这样:

Scanner in = new Scanner(System.in);
int i = 0;
while(!s.equals("end"))
{
    i++;
    String s = in.next();
    System.out.println("The value of i is: " + i + " and you entered " + s);
}

答案 12 :(得分:1)

如果问题是“为什么要重写它”,答案基本上就像其他人指出的那样,它现在是一个无限循环,而且它的可读性也不是很高。就个人而言,我将其重写为一个while循环,其他几个人已经指出了如何做,因为它使你的意图比一个计数器达到无穷大的for循环更清晰。不熟悉代码应该如何工作的人很容易将无限增量混淆成为编写代码的程序员的疏忽。

答案 13 :(得分:1)

这是一种不好的做法,因为它只有在下一个获得的令牌是“结束”时终止。它不会考虑像这样的情况。例如输入流结束。

所以,当流结束并且没有出现“结束”时,你会在s=null得到NullPointerExceptions.equals("end")

您可以更正它,例如将条件更改为in.hasNext() && !"end".equals(s)

初始化后,s也永远不会改变。

答案 14 :(得分:0)

上面的一些回答是正确的,说你写的是无限循环。但我想澄清为什么这是一个无限循环。您使用的 for 循环与您可能想到的其他形式不同:

String[] stringArray = { "1", "2", "3" };
for (String s : stringArray) {
   System.out.println(s);
}

在这种情况下,变量 s 在每次迭代时使用集合或数组中的下一个值进行初始化。但 for 循环的这种形式适用于集合和数组,不能与扫描程序类等迭代器一起使用。

您使用的 for 循环的形式不同之处在于,初始化子句(您有String s = in.next()的地方)第一次被称为 ONLY 环。第一次设置 s ,然后永远不会更改。

你可以像这样重写:

int i = 0;
for (String s = in.next(); !s.equals("end"); s = in.next()) {
    System.out.println("The value of i is: " + i++ + " and you entered " + s);
}

但这里的另一个坏处是没有空或结束检查。可以想象,如果不太可能在找到等于“结束”的字符串之前用完字符串。如果发生这种情况,那么 for 测试子句(中间的)会在尝试调用 equals() NullPointerException >方法。这绝对是不好的做法。我可能会像这样重写:

int i = 0;
while (in.hasNext()) {
    String s = in.next();
    if (s.equals("end")) {
        break;
    }
    System.out.println("The value of i is: " + i++ + " and you entered " + s);
}

如果你真的想要 for 循环而不是,那么最好这样做:

int i = 0;
for (Scanner in = new Scanner(System.in); in.hasNext();) {
    String s = in.next();
    if (s.equals("end")) {
        break;
    }
    System.out.println("The value of i is: " + i++ + " and you entered " + s);
}

在测试子句中针对字符串保留测试的最后一个变体如下所示:

int i = 0;
String s = "";
for (Scanner in = new Scanner(System.in);
     in.hasNext() && !s.equals("end"); 
     s = in.next()) {
    System.out.println("The value of i is: " + i++ + " and you entered " + s);
}

您还可以在s.equals("end")之前添加空检查以确保完全安全。

答案 15 :(得分:0)

for (int i = 0; in.hasNext(); i++) {
    String s = in.next();
    if (s.equals("end")) {
        break;
    }
    ...

无限循环,或无循环(当s最初为“结束”时)。

答案 16 :(得分:-1)

这可能不是一个好习惯,因为您正在将String s与字符串进行比较,但是您没有比较该值,而是在比较s值的内存位置。