Tokens, Lines, and the hasNext Cascade
Where you are: Week 0 review > Tokens, lines, and the hasNext cascade
Try This First
A program calls sc.nextInt() to read an age, then sc.nextLine() to read a full name on the next line, but the name comes back empty. Decide why before reading on.
Reveal
nextInt() reads the number but stops before the newline at the end of that line. The following nextLine() reads from the cursor to that newline, which is the empty rest of the number’s line. The fix is to call an extra nextLine() after nextInt() to consume the leftover newline.
Before You Start
Check each box you can do from memory. A box you cannot check yet is not a problem; it points you to a quick refresher, not a grade.
See Reading a File with Scanner if any of the above felt unfamiliar.
Not sure? Take the 60-second self-check.
Try each from memory, then read the answer under it.
- What does a
Scannerover a file let you do? Read the file piece by piece, the same way a keyboardScannerreads input. - What guards a read loop so it stops at the end of the file? A
hasNextstyle check, asked before each read.
What You Need To Walk In With
Walk into the next class able to state these:
- Match the guard to the read:
hasNextLinegoes withnextLine,hasNextIntgoes withnextInt,hasNextgoes withnext. A mismatch is the usual cause of a file-reading crash. - Line mode reads one record per line (
hasNextLine/nextLine). Token mode reads whitespace- separated pieces (hasNext/next, orhasNextInt/nextInt). hasNextInt()returns false at the end of the file and at the first token that is not an integer, so it doubles as a sentinel value detector.- After
nextInt(), an immediatenextLine()returns the empty remainder of that line.
You should be able to: pick line or token mode for a described file, and avoid the nextInt-then- nextLine trap.
How It Works
The file’s shape decides the mode:
| File format | Mode | Guard | Read |
|---|---|---|---|
| One record per line | Line | hasNextLine() |
nextLine() |
| Whitespace-separated words | Token | hasNext() |
next() |
| Integers, possibly several per line | Token, typed | hasNextInt() |
nextInt() |
Line mode:
while (sc.hasNextLine()) {
String line = sc.nextLine();
System.out.println(line);
}
Token mode for integers:
int sum = 0;
while (sc.hasNextInt()) {
sum = sum + sc.nextInt();
}
First time seeing "sentinel"? Open for a 20-second refresher.
A sentinel is a special value placed in data to signal “stop here.” Instead of counting items ahead of time, the loop watches for the sentinel and exits when it appears. A word like STOP at the end of an integer file is a classic example.
hasNextInt() returns false at the end of the file and at the first token that is not a valid integer. A file that ends with the word STOP makes hasNextInt() return false at STOP, so the loop stops on its own with no if inside it.
The nextInt then nextLine trap
nextInt() reads the number and leaves the cursor just before the newline. An immediate nextLine() reads from there to that newline and returns an empty string. Two standard fixes:
- Call an extra
sc.nextLine()right afternextInt()to consume the leftover newline, then read the real line. - Read every line with
nextLine()and convert withInteger.parseInt(line.trim()), so the modes never mix.
Worked Example: Predict, Then Check
A file holds the integers 10 20 30 on one line. The token loop above sums them. Predict the result.
Reveal
60. Each pass hasNextInt() peeks true and nextInt() reads the next integer: 10, then 20, then
- The fourth peek reaches the end of the file, returns false, and the loop exits with the sum 60.
A Common Mistake
The deepest file-reading bug is a guard that does not match its read, such as hasNextInt() guarding a nextLine(), or reading with nextLine() right after nextInt() without consuming the newline. Keep the guard and the read in the same family, and remember that nextInt() does not move past the end of its line. (Source: BJP (Reges and Stepp), Ch 6.)
Go Deeper (optional)
For the curious: a Scanner splits input into tokens on whitespace and also tracks line boundaries, so the two modes share one cursor. Mixing them is what causes the trap. Many programs avoid the issue entirely by reading whole lines and parsing each line themselves, which keeps one consistent mode and makes the cursor easy to reason about.
Check Yourself
Close the notes and answer each one from memory, then reveal it. Pulling an idea back from memory is one of the strongest ways to make it stick.
Check your understanding
Which guard matches a nextLine() read?
When does hasNextInt() return false?
After sc.nextInt() reads a number, an immediate sc.nextLine() returns what?
A file has one full name per line. Which mode fits?