0

Obviously, my real code is more complex, but here's an example:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in).useDelimiter("\n");
        String[] cmdSplit = null; 
        while (true) {
            while (input.hasNext()) {
                cmdSplit = input.next().split("\\s+");
                System.out.println("stuff");
            }
            for (int i = 0; i < cmdSplit.length; i++) System.out.println(cmdSplit[i]);
        }
    }
}

In the above example, the code takes input from System.in, splits it, and should output each piece. However, for some reason, the code after the inner while loop never executes. If I replace while with if, it works. If you test it, you can see it doesn't run infinitely, because it only prints "stuff" once, showing the loop runs once. What is the issue with the while loop?

beewall
  • 131
  • 1
  • 10

3 Answers3

3

Reading from System.in is different than reading from a file or other fixed-size source of input. The input doesn't necessarily exist until you create it, and so attempts to read it need to block until the input actually arrives (i.e. you type it). Try typing another line - you'll see the stuff message again; that will allow .hasNext() to return because there is now input.

To have .hasNext() return false the input source needs to be closed. For a command line application you can do this by sending the EOF signal (Ctrl+D on Linux) which tells the process stdin has no more input. That's not generally how you want a program to work, though, so if your intent is to only read one line and then move on, you should in fact be using an if instead of a while as you've tried to do. Later if you need to read more input you'll call .hasNext() again and your program will block there until the user passes more input.


As @user7 mentions your outer while (true) combined with while(input.hasNext()) is redundant. If you want to read only once get rid of the while (true) and use if (input.hasNext()). Otherwise if you want to read forever just combine the two loops:

while (input.hasNext()) {
  cmdSplit = input.next().split("\\s+");
  System.out.println("stuff");
  for (int i = 0; i < cmdSplit.length; i++) System.out.println(cmdSplit[i]);
} // Loop will terminate once stdin is closed, e.g. by the user sending EOF.
dimo414
  • 47,227
  • 18
  • 148
  • 244
  • Want to add a point here - there is no use in having the outer infinite loop as `input.hasNext()` is not going to return true thereafter (here it'll keep printing what it saw the last time) – Thiyagu Feb 21 '18 at 04:24
  • Is there any way to detect the end without sending EOF? – beewall Feb 21 '18 at 04:26
  • There isn't an end before EOF is sent :) Until EOF is sent the program can continue reading input from the user indefinitely. Instead you generally want to read the input you expect and then stop doing so once you've read enough. It's common for interactive programs to add an "escape" of some sort, such as breaking out of the loop if the input string is empty. The exact behavior you'll want depends on your specific use case. – dimo414 Feb 21 '18 at 04:30
  • I'll probably use if and splits or something. I *was* trying to read to the end of user input, but I guess it makes sense why you can't until they say it is over. – beewall Feb 21 '18 at 04:39
-1

Yes , your code won't go to the for loop because the Scanner.hasNext() will always listen to the console for inputs.

You have to break the loop in order to come out and go to the for loop.

   Scanner input = new Scanner(System.in).useDelimiter("\n");
    String[] cmdSplit = null;
    while (true) {
      while (input.hasNext()) {
        cmdSplit = input.next().split("\\s+");
        System.out.println("stuff");
        break;
      }
      for (String element : cmdSplit) {
        System.out.println(element);
      }
    }
prithivraj
  • 71
  • 1
  • 12
  • 1
    If your intent is to simply break after one pass through a `while` loop (as in `while (...) { ...; break; }` you could just use an `if` instead (`if (...) { ...; }`). – dimo414 Feb 21 '18 at 04:21
-1

The reason it is printing "stuff" only one time is because the hasNext() returned false.

Let me explain what I have observed.

To get "stuff" printed indefinately the assignment has to be removed. meaning once you assigned the input the scanner does not have any more token

The java.util.Scanner.hasNext() method Returns true if this scanner has another token in its input.

This will print indefinitely

 while (input.hasNext()) {
            // cmdSplit = input.next().split("\\s+");
            System.out.println("stuff");
        }
Tadele Ayelegn
  • 4,126
  • 1
  • 35
  • 30