What nextLine() actually reads
Scanner.nextLine() reads characters from the current cursor position up to and including the next line terminator, then returns everything before the terminator as a String. The terminator is consumed but not returned. The cursor lands one character past it.
// Suppose the file contains: Alice\nBob\nCarol\n
final Scanner sc = new Scanner(new File("names.txt"));
String first = sc.nextLine(); // "Alice" : cursor now between \n and 'B'
String second = sc.nextLine(); // "Bob"
String third = sc.nextLine(); // "Carol"
Three properties of nextLine() worth committing to memory:
1. The newline is consumed but not returned. The returned String has no \n at the end. Code that appends "\n" for printing is doing the right thing; code that strips a trailing newline from the return is acting on a newline that is not there. 2. Empty lines return empty strings. Two consecutive \n characters mean "an empty line." nextLine() returns "" and the cursor moves past the second newline. Code that filters out blank lines must compare against "" (or use String.isBlank() for whitespace-only lines). 3. The cursor's position before the call decides what is returned. If a previous nextInt() or next() left the cursor mid-line, nextLine() reads from that mid-line position to the next newline. The trap that follows a token-mode read with nextLine covers this in detail, and it is the single most common Scanner bug in CS1.
Line terminator details
Java's Scanner recognizes the three common line endings: \n (Unix), \r\n (Windows), \r alone (old Mac). All three are consumed and produce the same return. A file edited on Windows and read on Linux behaves the same way; the Scanner documentation calls this "line terminator portability."
The trade-off: the String returned never carries the original line ending. A program that needs to preserve "this file was Windows-style" must read the file with Files.readString or similar instead.
When the last line lacks a terminator
Some text files end without a final \n (Windows Notepad sometimes does this; so do programs that fail mid-write). The behavior is:
nextLine()reads the partial last line and returns it.- The cursor lands at end-of-stream.
hasNextLine()returnsfalseafter the read.
The lack of a trailing newline does not lose data. The last line is still returned by the last nextLine() call.
In other languages
- Python:
for line in f:includes the trailing\n;line.rstrip()is the typical fix. Java strips it for you. - C:
fgets(buf, sizeof buf, fp)includes the\nif the buffer was long enough;strcspnor manual trim removes it. - JavaScript (Node):
readline.Interface.on('line', ...)strips the line terminator like Java does.