Why does hasNextLine() never end?

Hit Ctrl + D to terminate input from stdin. (Windows: Ctrl + Z) or provide input from a command:

echo -e "abc\ndef" | java Program

When reading from System.in, you are reading from the keyboard, by default, and that is an infinite input stream... it has as many lines as the user cares to type. I think sending the control sequence for EOF might work, such as CTL-Z (or is it CTL-D?).

Looking at my good-ol' ASCII chart... CTL-C is an ETX and CTL-D is an EOT; either of those should work to terminate a text stream. CTL-Z is a SUB which should not work (but it might, since controls are historically interpreted highly subjectively).


CTRL-D is the end of character or byte stream for UNIX/Linux and CTRL-Z is the end of character or byte stream for Windows (a historical artifact from the earliest days of Microsoft DOS).

With the question code as written, an empty line won't exit the loop because hasNextLine() won't evaluate to false. It will have a line terminator in the input byte stream.

System.in is a byte stream from standard input, normally the console. Ending the byte stream will therefore stop the loop. Although nextLine() doesn't block waiting for input, hasNextLine() does. The only way the code terminates, as designed, is with CTRL-Z in Windows or CTRL-D in UNIX/Linux, which ends the byte stream, causes hasNextLine() not to block waiting for input and to return a boolean false which terminates the while loop.

If you want it to terminate with an empty line input you can check for non-empty lines as part of the loop continuation condition. The following code demonstrates how to change the basic question design that uses hasNextLine() and nextLine() to one that terminates if it gets an empty line or an end of input character (i.e. CTRL-Z in Windows or CTRL-D in UNIX/Linux). The additional code in the while condition uses a feature of assignment operators wherein they can be evaluated like an expression to return the value that was assigned. Since it is a String object, the String.equals() method can be used with the evaluation.

Other additional code just adds some printed output to make what is going on obvious.

// HasNextLineEndDemo.java
import java.util.*;

public class HasNextLineEndDemo {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        // this code is a bit gee-whiz
        // the assignment expression gets assigned sc.nextLine()
        // only if there is one because of the &&
        // if hasNextLine() is false, everything after the &&
        // gets ignored
        // in addition, the assignment operator itself, if
        // executed, returns, just like a method return,
        // whatever was assigned to str which, 
        // as a String object, can be tested to see if it is empty
        // using the String.equals() method
        int i = 1; // input line counter
        String str = " "; // have to seed this to other than ""
        System.out.printf("Input line %d: ", i); // prompt user
        while (sc.hasNextLine() && !(str = sc.nextLine()).equals("")) {
            System.out.printf("Line %d: ", i);
            System.out.println("'" + str + "'");
            System.out.printf("Input line %d: ", ++i);
        } // end while
        System.out.println("\nYOU'VE GOT THROUGH");
    } // end main
} // end class HasNextLineEndDemo

I had a similar problem with a socket input stream. Most solutions I found would still block the execution. It turns out there is a not-blocking check you can do with InputStream.available(). So in this case the following should work:

int x = System.in.available();
if (x!=0) {
    //Your code
}