Lesson 45Phase 5: Errors, files and the standard library
Scanner and console applications
Reading numbers and lines from the keyboard, building a small interactive program, and common Scanner traps.
By BasithUpdated 55 min
- Scanner
- System.in
- nextInt
- nextLine
- input buffer
- interactive loop
Every program you have written so far has done all the talking. It prints, it computes, it prints again, and it never once stops to ask you anything. Many real tools hold a conversation instead: they ask, you answer, they react. This lesson gives your programs ears, so they can read what a person types at the keyboard.
- Create a
Scannerthat reads from the keyboard, and explain whatSystem.inis. - Read a number with
nextIntornextDouble, one word withnext, and a whole line withnextLine. - Build a small interactive program that asks for a name and an age and greets the person.
- Check input with
hasNextIntbefore reading it, so a typo does not crash the program. - Recognise and fix the classic
nextInt-then-nextLinetrap that eats your input. - Read in a loop until the person types a sentinel value, or until the input runs out.
Scanner lives in java.util and you must import it. You also need loops for the interactive loops, if-else to react to what was typed, and Integer.parseInt from wrapper classes to turn text into a number.From a monologue to a conversation#
Until now, output went out through System.out. There is a matching door for input called System.in. Think of System.out as the program's mouth and System.in as its ear. On its own, System.in is awkward to use: it hands over raw bytes, one at a time, with no idea of numbers or words. The Scanner class wraps it and does that work for you, reading a whole number, a word or a line at a time.
A Scanner is an object. String lives in java.lang, which every program can use without an import, but Scanner lives in the package java.util, so you import it first, as you saw in packages and imports.
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("What is your name? "); String name = sc.nextLine(); System.out.println("Hello, " + name); }}Read it from top to bottom. The import line brings the name Scanner into scope so you can write it plainly. Then new Scanner(System.in) builds a scanner and points it at the keyboard. After that, sc.nextLine() waits until the person types something and presses Enter. Whatever they typed comes back as a String, which the program stores in name and then prints. Run it, then put your own name in the box and run it again.
System.out.print, with no ln. That keeps the cursor on the same line, so the person types their answer right after the question mark instead of on a fresh line below it.The reading methods, one job each#
A scanner has a small family of read methods, and each one reads a different shape of input. Picking the right one is most of the skill. These are the four you will use most:
nextInt()reads the next whole number and gives you anint.nextDouble()reads the next number that may have a decimal point and gives you adouble.next()reads a single token: one run of non-space characters, one word.nextLine()reads everything up to the end of the current line, spaces and all.
A scanner splits what you type into pieces at the whitespace: spaces, tabs and line breaks. Each piece is a token. If you type red green blue, that is three tokens. next() takes exactly one of them and stops at the space. nextLine() takes the rest of the line as one string, spaces included.
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("Type three words: "); String word = sc.next(); System.out.println("First word only: " + word); }}The person typed three words, but next() kept only the first, red. The scanner keeps typed text that has not been read yet in its input buffer, and green blue is still sitting there, waiting for a read call that never comes. That leftover is harmless here. Later on this page, leftover text in the buffer is the cause of the most common Scanner bug.
nextInt()42, as an int.nextDouble()3.5, as a double.next()nextLine()String.Ada Lovelace and presses Enter. Which call gives you the string "Ada Lovelace", with the space?input() hands you the whole line as a string, and you convert it yourself. A Scanner has a method for each shape, so nextInt() gives you an int with no conversion step, as long as you pick the method that matches what the person will type. The closest match to input() is IO.readln, from Java 25, near the end of this page.A first interactive program#
Here is a program that asks two questions and reacts. It asks for a name and an age, then greets the person and says how old they will be next year. Almost every console tool has this shape: prompt, read, prompt, read, then compute and respond.
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("What is your name? "); String name = sc.next(); System.out.print("How old are you? "); int age = sc.nextInt(); int nextYear = age + 1; System.out.println("Hello, " + name + ". Next year you will be " + nextYear + "."); }}Follow the conversation. The program prints the first prompt and reads. The first line of input is Aisha, so next() returns "Aisha". The program prints the second prompt and reads again. The next line is 20, so nextInt() returns the int 20. With both values in hand, it adds one and prints the greeting. Because age is a real int, the + 1 is arithmetic, not joining text.
When the input is not a number#
People make typos. Suppose someone types twenty at the How old are you? prompt. nextInt() cannot turn twenty into an int, so it throws an exception, the kind of error report you met in reading errors and debugging, and the program stops.
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("How old are you? "); int age = sc.nextInt(); System.out.println("Next year you will be " + (age + 1) + "."); }}InputMismatchException
The next piece of input did not match the type that was asked for.
The program stops on line 8 with an InputMismatchException: the next token did not match the type the program asked for. The last line of the report, at Main.main(Main.java:8), points at the line that asked for the number. In a terminal, Java's report also lists a few lines from inside the Scanner class itself, above that one.
Now change the input to 3000000000 and run it again. That token looks like a whole number, but it is too big for an int, so this time the report adds the detail For input string: "3000000000".
Check before you read: hasNextInt#
A scanner can look at the next token without reading it. hasNextInt() answers one question: is the next token a whole number? It returns true or false and leaves the token where it is. That makes a loop that keeps asking until the answer is usable:
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("How old are you? "); while (!sc.hasNextInt()) { String wrong = sc.next(); System.out.print(wrong + " is not a whole number. Try again: "); } int age = sc.nextInt(); System.out.println("Next year you will be " + (age + 1) + "."); }}With this input the loop body runs twice. twenty is not a whole number, so the loop throws it away with next() and asks again. Neither is 20.5. Then 20 arrives, hasNextInt() returns true, the loop ends, and nextInt() reads it. The next() inside the loop matters: hasNextInt() never moves past a token, so without it the loop would look at twenty forever.
Its relatives work the same way. hasNextDouble() checks for a number that may have a decimal point, hasNext() checks for any token at all, and hasNextLine() checks for another line. Each one answers yes or no and reads nothing.
seven. What does sc.hasNextInt() do?nextInt() throw, catch the InputMismatchException, and ask again. That uses try and catch, which exception handling teaches. hasNextInt() does the job with nothing new.The classic trap: nextInt then nextLine#
Here is the most common bug a beginner hits with Scanner, and almost everyone hits it once. You read a number, then want to read a full line of text afterward. The obvious code looks right and is wrong.
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("Enter your age: "); int age = sc.nextInt(); System.out.print("Enter your full name: "); String fullName = sc.nextLine(); System.out.println("Hello, '" + fullName + "' (age " + age + ")"); }}Run it and look at the console. The program never gave the person a chance to type a name. It printed the second prompt and then the greeting straight away, with fullName empty: the two quote marks have nothing between them. The second line of input, Aisha Khan, was never read. Step through it and stop on line 11, where the narration says what happened.
20 and press Enter, two things land in the buffer: the characters 20 and an invisible line break from the Enter key, which Java writes as \n. nextInt() reads the 20 and stops. It leaves the line break sitting there, unread. The next nextLine() reads from the current spot to the end of the line, finds only that leftover line break, and returns an empty string at once, without waiting for the person.import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int count = sc.nextInt(); String item = sc.nextLine(); String next = sc.nextLine(); System.out.println(count + " [" + item + "] [" + next + "]"); }}The keyboard input is two lines: 3, then blue pens. What does the program print?
The first nextLine() gets the empty rest of the line that held 3. The second one starts on a fresh line and gets blue pens. So the output is 3 [] [blue pens], and that extra call is exactly the fix.
The fix: eat the leftover line break#
The cure is one extra line. After the nextInt(), call sc.nextLine() once on its own and ignore what it returns. That spare call swallows the stranded line break, so the next nextLine() starts at the beginning of a fresh line.
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("Enter your age: "); int age = sc.nextInt(); sc.nextLine(); // consume the leftover line break after the number System.out.print("Enter your full name: "); String fullName = sc.nextLine(); System.out.println("Hello, '" + fullName + "' (age " + age + ")"); }}One throwaway sc.nextLine() between the number read and the line read is the whole fix. The name has a space in it, so nextLine() was the right tool, and with the leftover line break gone it captures Aisha Khan in full.
Key ideaReading a number with
nextIntornextDoubleleaves the Enter line break in the buffer. If anextLinecomes next, add a throwawaysc.nextLine()between them to clear it.
The other fix: read only whole lines#
The second way out is to never mix the two kinds of read. Read every answer as a whole line with nextLine(), and turn the lines that hold numbers into numbers yourself with Integer.parseInt. Each nextLine() takes its whole line, line break included, so nothing is ever left behind.
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("Enter your age: "); int age = Integer.parseInt(sc.nextLine().trim()); System.out.print("Enter your full name: "); String fullName = sc.nextLine(); System.out.println("Hello, '" + fullName + "' (age " + age + ")"); }}The trim() removes any spaces around the number before it is parsed, because parseInt refuses a space in front of the digits.
sc.nextLine() after every nextInt or nextDouble, or read everything with nextLine() and convert the numbers yourself.int n = sc.nextInt(); has just read 7 from a line the person ended with Enter. Which call comes back at once with an empty string?3 and blue pens prints 3 x blue pens.Reading in a loop until a sentinel#
One read is a single question. A real tool keeps asking until you are done. The usual pattern is to read over and over inside a loop, and stop when the person types a special agreed value that means “I am finished”. That value is called a sentinel, like a guard standing at the exit.
The program below keeps reading numbers and adding them to a running total. The sentinel is 0. As soon as the person types 0, the loop ends and the program reports the sum. Every other number goes into the total.
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int total = 0; System.out.print("Enter a number (0 to finish): "); int n = sc.nextInt(); while (n != 0) { total = total + n; System.out.print("Enter a number (0 to finish): "); n = sc.nextInt(); } System.out.println("Total: " + total); }}Walk through the run with the code beside it. The program reads one number before the loop, called the priming read, so the while condition has something to test. The first number is 5, which is not 0, so the loop body runs: it adds 5 to total, prompts, and reads again. The same happens for 12 and 3. Then 0 arrives: the condition n != 0 is now false, the loop stops, and the program prints the sum of 5, 12 and 3, which is Total: 20. The sentinel itself is never added, because the program reads it, tests it, and leaves before adding.
- 1Read once before the loop. This is the priming read that gives the condition a value to check.
- 2While the value is not the sentinel, do the work, then read the next value at the bottom of the loop.
- 3When the sentinel arrives, the condition fails and the loop ends without processing it.
Key ideaA sentinel loop reads once before the loop and again at the end of every pass, so the condition always tests the newest value and the sentinel itself is never processed.
0 because adding zero changes nothing, so it is safe to reserve as the stop signal. If 0 were a number you really wanted to total, you would need a different sentinel, perhaps a negative number, or a word such as done. The rule: pick a value the real data can never take.done. The keyboard input is apple pear on one line and plum done on the next. Put the lines in order so that it prints 3 words before done.Tap a line, then tap where it should go. Or use the arrows.
nextInt(). Some items are free, with a price of 0. Which sentinel is safe?Stop when the input runs out#
Sometimes there is no sentinel at all, and the program reads until there is nothing left. hasNextInt() returns false at the end of the input, and also when the next token is not a whole number, so it makes a natural loop condition:
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int total = 0; int count = 0; while (sc.hasNextInt()) { total = total + sc.nextInt(); count++; } System.out.println(count + " numbers, total " + total); }}This prints 3 numbers, total 20. The input has 5 and 12 on one line and 3 on the next, and that makes no difference, because nextInt() skips spaces and line breaks alike. On this page the input ends where the box ends. In a terminal, the person signals the end by pressing Ctrl+D on macOS and Linux, or Ctrl+Z and then Enter on Windows. A file always has an end, and the next lesson reads files with this same kind of loop.
72, 95, 68 it should print Highest: 95.Putting it together: a tiny menu#
Here is the shape of a complete little console app: a loop, a sentinel, and a branch on what was typed. It reads a command word each time and acts on it, stopping when the person types quit. Every entry is a single word read with next(), so there is no line-break trap to worry about.
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("Command (hello / bye / quit): "); String cmd = sc.next(); while (!cmd.equals("quit")) { if (cmd.equals("hello")) { System.out.println("The program says hi."); } else if (cmd.equals("bye")) { System.out.println("The program waves goodbye."); } else { System.out.println("Unknown command: " + cmd); } System.out.print("Command (hello / bye / quit): "); cmd = sc.next(); } System.out.println("Shutting down."); }}This is the same priming-read pattern as the adder, with a word as the sentinel and an if-else chain in the middle. dance is not a command, so it lands in the final else. The program compares strings with cmd.equals("quit"), never with ==, because == asks whether two variables point at the very same object while equals compares the text. That distinction was the heart of references and equality.
Scanner once, at the start of main, and pass it to any method that needs to read. Two scanners on System.in can fight over the input: the first one may read ahead and keep text that the second never sees. Calling close() on a scanner over System.in also closes System.in itself, so nothing can read the keyboard after that. A scanner on System.in can stay open until the program ends.Two other ways to read a line#
Java 25 added a small class called IO with methods for the console. IO.readln(prompt) prints the prompt, then reads one whole line and returns it as a String. IO lives in java.lang, so it needs no import.
public class Main { public static void main(String[] args) { String name = IO.readln("What is your name? "); int age = Integer.parseInt(IO.readln("How old are you? ")); IO.println("Hello, " + name + ". Next year you will be " + (age + 1) + "."); }}IO.readln always gives you text, so the age goes through Integer.parseInt. There is no trap here, because every call reads exactly one whole line. Read the keyboard with either IO.readln or a Scanner in one program, not both: the documentation warns that after the first readln call, any other use of System.in gives unspecified results.
You will also see older code read the keyboard with a BufferedReader wrapped around System.in. Its readLine() method returns one whole line, much like IO.readln. BufferedReader comes up properly in the next lesson, where it reads files.
Try it
Answer each one in your head or on paper first, then open the answer.
Scanner sc = new Scanner(System.in); set up, and what does System.in stand for?hello world and presses Enter. The program calls sc.next(). What string comes back, and what is left unread?nextLine() placed right after a nextInt() often comes back empty.nextInt() and then a city with next(). Does it need a throwaway nextLine() between them?4, 4 and 0, one per line. What does it print, and how many times does the loop body run?AskAgain.java, the keyboard input is twenty years on one line and 20 on the next. How many “is not a whole number” messages appear?Practice
Work through these on your own. Each one builds on this page.
next(), then their favourite quote with nextLine(), then prints them together. Make it work even though a line read follows a word read. To test it, open any program on this page full screen, replace its code with yours, and type your answers in the keyboard input box.double. Do not count or include the 0.hasNextInt() for words and decimals and an if for numbers out of range, then print the month's number back.add reads one number and adds it to a running total, show prints the current total, and quit stops.next() and nextLine(), and give one situation where choosing the wrong one would change what your program reads.Further reading#
Spotted a mistake, or a part that did not make sense? Report it by email