Java User Input with Scanner and Type Casting: nextInt, nextLine Bug, (int) and (double)
These are the notes for Java episode 4. You will learn why Java has no input() function, what System.in is, how to read the keyboard with Scanner (and why it needs an import), the reading methods nextInt, nextDouble, next and nextLine, the InputMismatchException, the famous skipped-nextLine bug and its fix, and type casting: (double) for a correct average, widening vs narrowing, (int) vs Math.round, char and int, and byte overflow. Every example below runs as-is in the SyntaxPilot compiler (type the input into the input box before you press Run).
The problem: a bill splitter that only knows one bill
A café owner loves the bill splitter from episode 3 and wants to use it at every table. But table 1 is ₹250 for 4 friends, table 2 is ₹1,480 for 6 friends, and the bill is written inside the code. For every table the owner has to open the code, change the number, compile and run, with a queue of hungry customers waiting.
The fix: don't write the bill in the code. Ask for it when the program runs, and let the waiter type it in.
Why there's no input()
Other languages have an input() function, so let's try it:
public class Main {
public static void main(String[] args) {
int bill = input();
System.out.println("Bill: " + bill);
}
}
Main.java:3: error: cannot find symbol
int bill = input();
^
symbol: method input()
location: class Main
Java has no built-in input function. It does give you the keyboard, as System.in, but that is a raw stream of keystrokes: a 2, a 5, a 0, an Enter.
| In a house | In Java |
|---|---|
| The water main: a raw flow into the house | System.in: raw keystrokes |
| A tap with a filter gives you a glass of water | Scanner turns the keystrokes into proper values |
| You ask for one glass at a time | sc.nextInt(): one value at a time |
Scanner and import
We make a Scanner and fit it onto the keyboard pipe:
Scanner sc = new Scanner(System.in);
But without an import:
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int bill = sc.nextInt();
System.out.println("Bill: " + bill);
}
}
Main.java:3: error: cannot find symbol
Scanner sc = new Scanner(System.in);
^
symbol: class Scanner
location: class Main
Why do System and String work but not Scanner? Java's toolboxes are called packages.
| At home | In Java |
|---|---|
| A spoon is always on the dining table | java.lang (System, String, Math) is always imported for you |
| A spanner lives in the toolbox; fetch it first | Scanner lives in the java.util package |
| Bring it to the kitchen | import java.util.Scanner; at the very top of the file |
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter the bill:");
int bill = sc.nextInt();
System.out.println("You typed: " + bill);
}
}
Input:
250
Output:
Enter the bill:
You typed: 250
The number came from outside the program. Note: the SyntaxPilot input box does not echo what you type into the output; in a real terminal you would see 250 next to the prompt.
importgoes above the class, at the very top of the file.import java.util.*;imports every class injava.util; importing justScanneris clearer.
Asking the Scanner for values
| Method | Returns | Reads |
|---|---|---|
sc.nextInt() |
int |
a whole number |
sc.nextDouble() |
double |
a decimal |
sc.next() |
String |
one word (stops at a space) |
sc.nextLine() |
String |
the whole line, spaces and all |
Scanner splits the input wherever there is a space or an Enter. So next() stops at the first space: type Riya Sharma and next() gives only Riya. (There is also nextLong(), nextBoolean() and so on; there is no nextChar(), use sc.next().charAt(0).)
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Your name:");
String name = sc.nextLine();
System.out.println("Your age:");
int age = sc.nextInt();
System.out.println("Height in metres:");
double h = sc.nextDouble();
System.out.println("Hi " + name + "! Age " + age + ", height " + h);
}
}
Input (one value per line):
Riya Sharma
19
1.62
Output:
Your name:
Your age:
Height in metres:
Hi Riya Sharma! Age 19, height 1.62
Three types, three methods, all from the keyboard. Match the method to the type you want.
next() vs nextLine() on the same input Riya Sharma:
String first = sc.next();
String rest = sc.nextLine();
System.out.println("next(): [" + first + "]");
System.out.println("rest: [" + rest + "]");
Output:
next(): [Riya]
rest: [ Sharma]
Wrong input: InputMismatchException
Users don't always behave. The waiter types abc where nextInt() expects a number:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter the bill:");
int bill = sc.nextInt();
System.out.println("Bill: " + bill);
}
}
Input: abc
Enter the bill:
Exception in thread "main" java.util.InputMismatchException
This is not a compile error: the code was fine. It crashed while running because the input did not match the type, like a cash counter that only accepts notes being handed a bus ticket. Typing a decimal like 99.5 into nextInt() gives the same exception. Later in the course you will learn to catch it (try/catch) and ask again politely.
Related: if there is no input at all and you call nextInt(), you get java.util.NoSuchElementException. On SyntaxPilot that means you forgot to fill in the input box.
The skipped nextLine bug
A registration form asks for age first, then the full name. You type 19 and press Enter, then Riya Sharma:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter age:");
int age = sc.nextInt();
System.out.println("Enter full name:");
String name = sc.nextLine();
System.out.println("Name: [" + name + "], age: " + age);
}
}
Input:
19
Riya Sharma
Output:
Enter age:
Enter full name:
Name: [], age: 19
The name is empty, and there is no error. What happened:
nextInt()takes the19, but only the number. The Enter you pressed is left behind in the pipe.nextLine()reads up to the next Enter, and the very first thing it finds is that leftover Enter. So it returns an empty line.
The fix: after nextInt(), call sc.nextLine(); once, just to sweep up the leftover Enter:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Enter age:");
int age = sc.nextInt();
sc.nextLine();
System.out.println("Enter full name:");
String name = sc.nextLine();
System.out.println("Name: [" + name + "], age: " + age);
}
}
Output:
Enter age:
Enter full name:
Name: [Riya Sharma], age: 19
The same thing happens after nextDouble() and next(). Another common fix is to read every line with nextLine() and convert it yourself: int age = Integer.parseInt(sc.nextLine().trim());. This one shows up in interviews and in every beginner's first project.
Type casting: (double) for a correct average
A student scores 86 and 85. The total is 171, and both sum and count are ints:
public class Main {
public static void main(String[] args) {
int sum = 171;
int count = 2;
System.out.println("Average: " + sum / count);
System.out.println("Average: " + (double) sum / count);
}
}
Output:
Average: 85
Average: 85.5
The first line is the integer-division trap from episode 3: int / int gives an int, and half a mark vanishes. Last time we fixed it by writing 250.0, but here the value is in a variable; we cannot add .0 to a variable.
A cast says "treat this value as this type, just for this calculation": write the type in round brackets in front of the value. (double) sum turns 171 into 171.0, so the division becomes decimal division. sum itself is still an int; the cast only changes this one use.
Cast before dividing, not after
System.out.println("Average: " + (double) (sum / count));
Output:
Average: 85.0
The division inside the brackets happened first, as int, and lost the half. Then the cast just added .0 to 85. Likewise double avg = sum / count; gives 85.0: the result is already cut before it reaches the double box.
Cast before dividing:
(double) sum / count.
Widening vs narrowing
| In the kitchen | In Java |
|---|---|
| Pour a glass into a big jug: it always fits | int → double: automatic (widening) |
| Pour a jug into a small glass: it may spill | double → int: you must cast (narrowing) |
| What spills is gone | (int) 99.99 is 99: the decimal is cut off |
public class Main {
public static void main(String[] args) {
double price = 99.99;
int rupees = price;
}
}
Main.java:4: error: incompatible types: possible lossy conversion from double to int
"Lossy" means you would lose something. Java is asking: are you sure you want to spill the decimal? You say yes with a cast:
public class Main {
public static void main(String[] args) {
double price = 99.99;
int rupees = (int) price;
System.out.println("Cast: " + rupees);
System.out.println("Round: " + Math.round(price));
int marks = 85;
double d = marks;
System.out.println("Widened: " + d);
}
}
Output:
Cast: 99
Round: 100
Widened: 85.0
(int)cuts the decimal (towards zero:(int) -9.99is-9).Math.roundrounds properly. Careful:Math.round(double)returns along, soint r = Math.round(99.99);fails withpossible lossy conversion from long to int; write(int) Math.round(99.99).int → doubleneeds no cast at all.
Shopkeepers round. Casts cut.
Which conversions are automatic?
byte → short → int → long → float → double
- Left to right = widening: automatic, nothing lost.
- Right to left = narrowing: write the cast, e.g.
(int), and you might lose something. - Characters are numbers underneath:
(int) 'A'is65,(char) 66is'B'.
char, int and wrap-around
A byte can only hold -128 to 127. Force 130 into it:
public class Main {
public static void main(String[] args) {
System.out.println((int) 'A');
System.out.println((char) 66);
int big = 130;
byte small = (byte) big;
System.out.println(small);
}
}
Output:
65
B
-126
130 did not fit, so it wrapped around, like a car's odometer rolling over from all nines back to zero. No error, just a weird number. A cast says "trust me", so make sure the value fits. Without the cast, Java refuses:
byte small = 130;
Main.java:3: error: incompatible types: possible lossy conversion from int to byte
More char facts (verified):
| Code | Output | Why |
|---|---|---|
'A' + 1 |
66 |
char + int is an int |
(char) ('A' + 1) |
B |
cast the sum back to char |
char c = 'A'; c++; |
B |
++ keeps the type |
(int) 3000000000L |
-1294967296 |
a long too big for int wraps around |
Common mistakes (and the real error messages)
| Mistake | Code | Error / result |
|---|---|---|
| Using Scanner without the import | Scanner sc = new Scanner(System.in); |
cannot find symbol (symbol: class Scanner) |
Expecting an input() function |
int bill = input(); |
cannot find symbol (symbol: method input()) |
| Wrong type typed | nextInt() given abc |
Exception in thread "main" java.util.InputMismatchException |
| No input given | nextInt() with an empty input box |
java.util.NoSuchElementException |
nextInt() then nextLine() |
age, then name | no error, name is empty; fix: extra sc.nextLine(); |
double into int |
int rupees = price; |
incompatible types: possible lossy conversion from double to int |
| Cast after dividing | (double) (sum / count) |
no error, 85.0 instead of 85.5 |
Rounding into an int |
int r = Math.round(99.99); |
possible lossy conversion from long to int |
Big literal into byte |
byte small = 130; |
possible lossy conversion from int to byte |
Mini project: bill splitter v2
The café owner finally gets the program they wanted:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("Bill amount:");
double bill = sc.nextDouble();
System.out.println("Number of friends:");
int friends = sc.nextInt();
System.out.println("Tip percent:");
int tipPercent = sc.nextInt();
double total = bill + bill * tipPercent / 100;
double each = total / friends;
System.out.println("Total: " + total);
System.out.println("Each pays: " + each);
System.out.println("Rounded up: " + (int) Math.ceil(each));
}
}
Input (table 2):
1250
3
10
Output:
Bill amount:
Number of friends:
Tip percent:
Total: 1375.0
Each pays: 458.3333333333333
Rounded up: 459
billis adouble, sobill * tipPercent / 100is decimal maths.- Nobody carries paise, so
Math.ceilrounds each share up (459.0), and(int)turns it into a whole number. - For the next table the owner just types new numbers. No code changes, ever.
Practice
- Read a temperature in Celsius and print it in Fahrenheit (
F = C × 9 / 5 + 32). - Read the age and then the full name, and beat the
nextLinebug. - Read three
intmarks and print the exact average. - Read a letter and print the letter that comes after it.
- Why does
9 / 5 * c + 32give the wrong Fahrenheit value for anint c?
Solutions and hints
double c = sc.nextDouble(); double f = c * 9 / 5 + 32; System.out.println(c + " C = " + f + " F");. Input37prints37.0 C = 98.6 F.int age = sc.nextInt(); sc.nextLine(); String name = sc.nextLine();int sum = m1 + m2 + m3; System.out.println("Average: " + (double) sum / 3);. Input80 85 86printsAverage: 83.66666666666667.char ch = sc.next().charAt(0); char nextCh = (char) (ch + 1);. InputKprintsAfter K comes L.9 / 5is integer division and gives1, so forc = 37you get69instead of98. Multiply first (c * 9 / 5 + 32gives98) or use adouble.
Quick quiz
What will this print?
double d = 9.99;
int i = (int) d;
System.out.println(i + 0.5);
- A.
10.49 - B.
10 - C.
9.5 - D.
9
Answer
C. 9.5. (int) 9.99 cuts the decimal, so i is 9 (a cast cuts, it does not round). Then 9 + 0.5 widens to a double: 9.5.
Interview questions
- How do you read input from the keyboard in Java? Why does
Scannerneed an import butStringdoes not? - What is the difference between
next()andnextLine()? - Why does
nextLine()return an empty string afternextInt(), and how do you fix it? - What is
InputMismatchException? Is it a compile-time or a runtime error? - What is type casting? What is the difference between widening and narrowing?
- What is the difference between
(int) 9.99andMath.round(9.99)? What type doesMath.round(double)return? - What is
(byte) 130, and why? - What is the output of
(double) 7 / 2vs(double) (7 / 2)? (3.5vs3.0)
Summary
System.inis the raw keyboard pipe;Scanneris the tap that turns keystrokes into values.import java.util.Scanner;goes at the very top;java.langis imported automatically.nextInt,nextDouble,next(one word) andnextLine(whole line).- Wrong input type:
InputMismatchExceptionat runtime. - After
nextInt(), add onesc.nextLine();before reading a line. (double) sum / countfor a correct average: cast before dividing.- Widening (
int → double) is automatic; narrowing (double → int) needs a cast. (int)cuts,Math.roundrounds,Math.ceilrounds up; values that don't fit wrap around.
Next episode: our program can listen now, but it treats every input the same. What if the bill is zero, or the age is under 18? Next, the program learns to make decisions with if, else and switch.