Keyboard Input with Scanner
Today, for the first time, your program stops and waits for what you type.
By the end of this lecture you will be able to
- Explain the roles of input, processing and output in any program
- Set up
Scannerwith an import andnew, and read from the keyboard with it - Choose the right read method for each data type, and read a single character when needed
- Write a clear prompt before every read
- Diagnose and fix the trap of
nextIntfollowed bynextLine - Explain
InputMismatchExceptionand write calculation programs that interact with the user
In this lecture
- Until today, every program you wrote gives the same answer on every run
- Now your program stops and waits for you
- Three lines connect your program to the keyboard
- Each data type has its own read method
- A prompt tells the user what to type
nextreads a word, andnextLinereads the rest of the line- There is no
nextChar, so we take the first character of a word nextIntleaves the Enter behind, andnextLinepicks it up- The fix: consume the Enter with an extra
nextLine - If the user types text instead of a number, the program stops with an exception
- A calculator: two inputs and four operations
- Rectangle area: start by asking what the inputs are
- Temperature conversion: one formula for any value the user types
- Final exercise: a student card from the keyboard
- Review questions
Until today, every program you wrote gives the same answer on every run
Every value so far is one we wrote inside the code ourselves. Run the next program ten times and it greets Sara ten times. To greet anyone else, you must open the code and change it.
A program that only knows Sara
Run it twice. Could someone who knows no Java make it greet them by name?
public class FixedGreeting {
public static void main(String[] args) {
String name = "Sara";
System.out.println("Hello, " + name + "!");
}
}Hello, Sara!
What comes from outside the program: an amount you type at a cash machine, or a student's marks.
What the program does with the values: checks the balance, or calculates the average.
What the program shows: the cash and receipt, or the final average.
Now your program stops and waits for you
This is a special moment in your journey: the next program does not know its answer when you press Run, because part of that answer is still with you.
Your first program that listens
Press Run. The program stops and an input box appears. Type your name and press Enter. Then run it again with a classmate's name: the same code, a different answer.
import java.util.Scanner;
public class Greeting {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("What is your name? ");
String name = input.nextLine();
System.out.println("Hello, " + name + "!");
}
}Three lines connect your program to the keyboard
Scanner is a ready-made class in the java.util package. Write this line at the top of the file, before class and after package if there is one.
import java.util.Scanner;Make one reader and name it. System.in means the keyboard. The name input is our choice.
Scanner input = new Scanner(System.in);Ask the reader for the next value and put it in a variable of the right type.
int age = input.nextInt();The compiler does not know Scanner
We forgot one line. Add it so the program works.
public class Ready {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Scanner is ready");
}
}cannot find symbolShow the fix
import java.util.Scanner;
public class Ready {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Scanner is ready");
}
}Scanner is ready
Why? Scanner is not among the basics the compiler knows automatically. The message says it cannot find the symbol and never mentions an import, so remember this cause whenever you see it with Scanner.
Read from where?
We created the reader without telling it where to read from.
import java.util.Scanner;
public class Ready {
public static void main(String[] args) {
Scanner input = new Scanner();
System.out.println("Scanner is ready");
}
}no suitable constructor found for Scanner(no arguments)Show the fix
import java.util.Scanner;
public class Ready {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Scanner is ready");
}
}Scanner is ready
Why? Scanner needs a source to read from and does not pick the keyboard by itself. The message is long and scary, but "no arguments" says it all: you gave it nothing between the parentheses.
Each data type has its own read method
| Method | Reads | Type | User types |
|---|---|---|---|
nextInt() | A whole number | int | 19 |
nextDouble() | A decimal number | double | 3.75 |
next() | One word, up to the first space | String | Sara |
nextLine() | The whole line, spaces included | String | Sara Ali |
nextBoolean() | true or false | boolean | true |
Four reads in one program
Run the program and answer each question. Notice that the program stops at each read, in order.
import java.util.Scanner;
public class Profile {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Age: ");
int age = input.nextInt();
System.out.print("GPA: ");
double gpa = input.nextDouble();
System.out.print("City: ");
String city = input.next();
System.out.print("Passed (true or false): ");
boolean passed = input.nextBoolean();
System.out.println("Age: " + age);
System.out.println("GPA: " + gpa);
System.out.println("City: " + city);
System.out.println("Passed: " + passed);
}
}Which method fits reading a book price such as 12.5?
next() could read the value, but it gives you text that you cannot multiply or add as a number.You want to read a full address such as 12 Omar Street. Which method fits?
next() stops at the first one, reading only 12. nextLine() reads up to the Enter key.A prompt tells the user what to type
Scanner prints nothing. If you print no message before the read, the user faces a silent program and has no idea what it wants.
A silent program
Run it as if you had never seen the code: what do you type? Then add a message before each read using print, such as "Length in metres: ".
import java.util.Scanner;
public class Silent {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
double length = input.nextDouble();
double price = input.nextDouble();
System.out.println(length * price);
}
}We prefer print for prompts because it leaves the cursor on the same line, so the user types beside the question. println moves to a new line.
Both styles together
This lab gives the program the values 19 and 3.5 automatically. Compare how the two prompts look in the output.
import java.util.Scanner;
public class Prompts {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Enter your age:");
int age = input.nextInt();
System.out.print("Enter your GPA: ");
double gpa = input.nextDouble();
System.out.println("Age " + age + ", GPA " + gpa);
}
}Enter your age: Enter your GPA: Age 19, GPA 3.5
next reads a word, and nextLine reads the rest of the line
Picture what you type as a strip of characters passing in front of Scanner. Each read takes a piece of the strip and moves on. Whatever is not read stays there for the next read.
The user typed Sara Ali Omar then Enter. What does the program print?
import java.util.Scanner;
public class Words {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String first = input.next();
String rest = input.nextLine();
System.out.println("[" + first + "]");
System.out.println("[" + rest + "]");
}
}Show the output
[Sara] [ Ali Omar]
Why? next takes the first word and stops before the space, so nextLine starts at that space and takes the rest. The square brackets reveal a space your eyes would otherwise miss.
Try it yourself
Run it and type a two-word name. Then change next to nextLine and run it again with the same name.
import java.util.Scanner;
public class WordOrLine {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Full name: ");
String name = input.next();
System.out.println("Welcome, " + name);
}
}There is no nextChar, so we take the first character of a word
char grade = input.next().charAt(0);next() gives a string, and charAt(0) takes the character at position 0, the first one.Read a grade
Run it and type B. Then run it and type Excellent. Then change 0 to 1 and run it again with Excellent.
import java.util.Scanner;
public class Grade {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Your grade: ");
char grade = input.next().charAt(0);
System.out.println("Grade stored: " + grade);
}
}The user typed Hello. What does the program print?
import java.util.Scanner;
public class FirstLetter {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
char letter = input.next().charAt(0);
System.out.println(letter);
}
}Show the output
H
Why? The 0 is the position of the character, not what gets printed. A char holds only one character, so H stays and the rest of the word is ignored.
A string in a char box
This is what happens if you write char grade = input.next();. Fix it so the program prints A.
public class CharBox {
public static void main(String[] args) {
String word = "A";
char grade = word;
System.out.println(grade);
}
}incompatible types: String cannot be converted to charShow the fix
public class CharBox {
public static void main(String[] args) {
String word = "A";
char grade = word.charAt(0);
System.out.println(grade);
}
}A
Why? Even a one-letter string is still a String. The compiler does not turn it into a char for you; you must take the character out with charAt(0).
nextInt leaves the Enter behind, and nextLine picks it up
This is the most famous Scanner trap, and every one of you will fall into it once. The code looks perfectly correct and compiles without error. Try it first: type your age, press Enter, and wait for the name question.
The program that does not wait
Run it. Did you get a chance to type your name?
import java.util.Scanner;
public class Trap {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Age: ");
int age = input.nextInt();
System.out.print("Name: ");
String name = input.nextLine();
System.out.println("[" + name + "] is " + age);
}
}The input here is two ready lines: 19 then Sara Ali. What does the program print?
import java.util.Scanner;
public class Trap {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Age: ");
int age = input.nextInt();
System.out.print("Name: ");
String name = input.nextLine();
System.out.println("[" + name + "] is " + age);
}
}Show the output
Age: Name: [] is 19
Why? nextInt took only the digits 19. The Enter stayed on the strip, so nextLine found it at once and took it as the end of an empty line. Nobody read Sara Ali.
| Read | What it takes | What stays on the strip |
|---|---|---|
nextInt() | 19 | The Enter, then Sara Ali |
nextLine() | Nothing but the Enter | Sara Ali, which nobody reads |
The fix: consume the Enter with an extra nextLine
We add one line after nextInt that takes the Enter and throws it away, without saving it in any variable. The strip is then clean, and nextLine waits for the real name.
The fix with the same input
The input is ready: 19 then Sara Ali. Compare the output with the previous one.
import java.util.Scanner;
public class TrapFixed {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Age: ");
int age = input.nextInt();
input.nextLine(); // Throw away the Enter left by nextInt
System.out.print("Name: ");
String name = input.nextLine();
System.out.println("[" + name + "] is " + age);
}
}Age: Name: [Sara Ali] is 19
Now you type
Run it and type your age and full name. This time the program waits for you. Press "Debug line by line" and watch where it stops at each read, then delete the extra line and compare.
import java.util.Scanner;
public class TrapFixedLive {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Age: ");
int age = input.nextInt();
input.nextLine();
System.out.print("Name: ");
String name = input.nextLine();
System.out.println("Hello " + name + ", you are " + age);
}
}| First read | Next read | A trap? |
|---|---|---|
nextInt() | nextInt() | No: it skips the Enter |
nextInt() | next() | No: it skips the Enter |
nextDouble() | nextLine() | Yes: the same trap |
next() | nextLine() | Yes: the same trap |
nextLine() | nextInt() | No: nextLine takes its Enter along |
Which order needs an extra nextLine between the two reads?
nextLine comes after a method that leaves the Enter behind. The other methods skip spaces and Enters while looking for their value, so they are unaffected.Age, then name
Print the prompt Age: and read a whole number, then print the prompt Name: and read a whole line, then print Sara Ali is 19 using the values you read.
import java.util.Scanner;
public class AgeThenName {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
// Read the age, then the full name, then print the sentence
}
}19 Sara Ali
Age: Name: Sara Ali is 19
Hint 1
If the name comes out empty, you fell into the trap.
Hint 2
Add input.nextLine(); right after nextInt.
Solution
import java.util.Scanner;
public class AgeThenName {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Age: ");
int age = input.nextInt();
input.nextLine();
System.out.print("Name: ");
String name = input.nextLine();
System.out.println(name + " is " + age);
}
}If the user types text instead of a number, the program stops with an exception
The compiler checks the code before it runs, but it cannot know what the user will type later. So this error appears only while running, and it is called an exception. Let us cause one on purpose.
Break the program on purpose
Run it and type 19. Then run it and type abc, and read the explanation shown under the output. Then try 19.5: what do you expect?
import java.util.Scanner;
public class BreakIt {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("How old are you? ");
int age = input.nextInt();
System.out.println("Next year you will be " + (age + 1));
System.out.println("Goodbye");
}
}The user typed abc. What appears in the normal output, leaving the error message aside?
import java.util.Scanner;
public class Stops {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Start");
int age = input.nextInt();
System.out.println("Age: " + age);
System.out.println("End");
}
}Show the output
Start
Why? The exception stops the program at the line where it happened, so the lines after it never run. And abc does not become zero: no value was ever stored in age.
| Method | User types | Result |
|---|---|---|
nextInt() | abc | InputMismatchException |
nextInt() | 19.5 | InputMismatchException |
nextDouble() | abc | InputMismatchException |
nextDouble() | 19 | 19.0 |
nextBoolean() | yes | InputMismatchException |
next() | 19 | The string "19" |
The user typed 19 for nextDouble. What does the program print?
import java.util.Scanner;
public class WholeInDouble {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
double value = input.nextDouble();
System.out.println(value);
}
}Show the output
19.0
Why? Every whole number is also a valid decimal, so nextDouble accepts it. The reverse fails: 19.5 is not a whole number, so nextInt rejects it.
A calculator: two inputs and four operations
- InputRead two
doublenumbers with a prompt for each. - ProcessingCalculate the sum, difference, product and quotient.
- OutputPrint each result on its own line, with text that explains it.
Your calculator
Try 7 and 2. Then try 5 and 0: notice the result Infinity for the division. Then hand the calculator to a classmate and ask them to test it.
import java.util.Scanner;
public class Calculator {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("First number: ");
double a = input.nextDouble();
System.out.print("Second number: ");
double b = input.nextDouble();
System.out.println(a + " + " + b + " = " + (a + b));
System.out.println(a + " - " + b + " = " + (a - b));
System.out.println(a + " * " + b + " = " + (a * b));
System.out.println(a + " / " + b + " = " + (a / b));
}
}The input: 7 then 2. Notice the parentheses around the sum. What does the program print?
import java.util.Scanner;
public class Sum {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
double a = input.nextDouble();
double b = input.nextDouble();
System.out.println("Sum: " + a + b);
System.out.println("Sum: " + (a + b));
}
}Show the output
Sum: 7.02.0 Sum: 9.0
Why? This is the trap from the variables lecture, and it matters more now that the values come from the user. Without parentheses the numbers are stuck onto the text; with them they are added first.
Rectangle area: start by asking what the inputs are
| Question | Answer |
|---|---|
| What are the inputs? | Width and height, possibly with a fraction |
| What is the processing? | width * height, 2 * (width + height) |
| What is the output? | The area and the perimeter |
Rectangle area and perimeter
Print the prompt Width: and read a decimal number, then the prompt Height: and read a decimal number. Then print Area: followed by the area on one line, and Perimeter: followed by the perimeter on the next.
import java.util.Scanner;
public class Rectangle {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
// Read the width and height, calculate, then print
}
}3 4
Width: Height: Area: 12.0 Perimeter: 14.0
Hint 1
Use nextDouble for both values, even if a whole number is typed.
Hint 2
The perimeter needs parentheses: 2 * (width + height).
Solution
import java.util.Scanner;
public class Rectangle {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Width: ");
double width = input.nextDouble();
System.out.print("Height: ");
double height = input.nextDouble();
double area = width * height;
double perimeter = 2 * (width + height);
System.out.println("Area: " + area);
System.out.println("Perimeter: " + perimeter);
}
}Temperature conversion: one formula for any value the user types
The formula: F = C * 9 / 5 + 32. We use printf to show one decimal place, as we learned last lecture.
Celsius to Fahrenheit
Try 37, 100 and -40. What is odd about the last one?
import java.util.Scanner;
public class Temperature {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Celsius: ");
double celsius = input.nextDouble();
double fahrenheit = celsius * 9 / 5 + 32;
System.out.printf("%.1f C = %.1f F%n", celsius, fahrenheit);
}
}The input is 25. What does the program print?
import java.util.Scanner;
public class Weather {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Celsius: ");
double celsius = input.nextDouble();
System.out.printf("%.1f F%n", celsius * 9 / 5 + 32);
}
}Show the output
Celsius: 77.0 F
Why? print keeps the prompt on the same line, and automatic input does not appear in the output. The calculation is 25 × 9 = 225, then ÷ 5 = 45, then + 32 = 77.
Fahrenheit to Celsius
Print the prompt Fahrenheit: and read a decimal number, convert it with the formula C = (F - 32) * 5 / 9, and print the result as 212.0 F = 100.0 C, with one decimal place for each value.
import java.util.Scanner;
public class ToCelsius {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
// Read the temperature, convert it, then print with printf
}
}212
Fahrenheit: 212.0 F = 100.0 C
Hint 1
Do not forget the parentheses around F - 32.
Hint 2
Use the template "%.1f F = %.1f C%n".
Solution
import java.util.Scanner;
public class ToCelsius {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Fahrenheit: ");
double fahrenheit = input.nextDouble();
double celsius = (fahrenheit - 32) * 5 / 9;
System.out.printf("%.1f F = %.1f C%n", fahrenheit, celsius);
}
}Final exercise: a student card from the keyboard
In the variables lecture we wrote the values of this card inside the code. Today the user types them, so one program works for every student at the university.
Student card
Read in order: Age: a whole number, then Name: a whole line, then GPA: a decimal number, then Grade: one character. Then print Sara Ali, age 19 on one line and GPA 3.75, grade A on the next, with two decimal places for the GPA.
import java.util.Scanner;
public class StudentCardInput {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
// Read age, name, GPA and grade, then print the card
}
}19 Sara Ali 3.75 A
Age: Name: GPA: Grade: Sara Ali, age 19 GPA 3.75, grade A
Hint 1
The name comes after nextInt: remember the trap?
Hint 2
Read the character with input.next().charAt(0).
Hint 3
Use printf with %.2f for the GPA and %c for the character.
Solution
import java.util.Scanner;
public class StudentCardInput {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.print("Age: ");
int age = input.nextInt();
input.nextLine();
System.out.print("Name: ");
String name = input.nextLine();
System.out.print("GPA: ");
double gpa = input.nextDouble();
System.out.print("Grade: ");
char grade = input.next().charAt(0);
System.out.println(name + ", age " + age);
System.out.printf("GPA %.2f, grade %c%n", gpa, grade);
}
}Review questions
What does cannot find symbol mean on the line that has Scanner?
Scanner without import java.util.Scanner;.When does InputMismatchException appear?
Why do we usually use print, not println, for a prompt?
Scanner alone, and print leaves the cursor right after the message.The input: 3.5 then Sara. What does the program print?
import java.util.Scanner;
public class ReviewTrap {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
double gpa = input.nextDouble();
String name = input.nextLine();
System.out.println("[" + name + "] " + gpa);
}
}Show the output
[] 3.5
Why? The trap is not unique to nextInt. Every method that reads a value but not the whole line leaves the Enter behind, and nextDouble is one of them.