</>SyntaxPilot
Notes › Java › Episode 4

Java User Input with Scanner and Type Casting: nextInt, nextLine Bug, (int) and (double)

▶ Watch the videoTry the code in the compilerAll Java notes

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.

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:

  1. nextInt() takes the 19, but only the number. The Enter you pressed is left behind in the pipe.
  2. 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

Shopkeepers round. Casts cut.

Which conversions are automatic?

byte → short → int → long → float → double

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

Practice

  1. Read a temperature in Celsius and print it in Fahrenheit (F = C × 9 / 5 + 32).
  2. Read the age and then the full name, and beat the nextLine bug.
  3. Read three int marks and print the exact average.
  4. Read a letter and print the letter that comes after it.
  5. Why does 9 / 5 * c + 32 give the wrong Fahrenheit value for an int c?
Solutions and hints
  1. double c = sc.nextDouble(); double f = c * 9 / 5 + 32; System.out.println(c + " C = " + f + " F");. Input 37 prints 37.0 C = 98.6 F.
  2. int age = sc.nextInt(); sc.nextLine(); String name = sc.nextLine();
  3. int sum = m1 + m2 + m3; System.out.println("Average: " + (double) sum / 3);. Input 80 85 86 prints Average: 83.66666666666667.
  4. char ch = sc.next().charAt(0); char nextCh = (char) (ch + 1);. Input K prints After K comes L.
  5. 9 / 5 is integer division and gives 1, so for c = 37 you get 69 instead of 98. Multiply first (c * 9 / 5 + 32 gives 98) or use a double.

Quick quiz

What will this print?

double d = 9.99;
int i = (int) d;
System.out.println(i + 0.5);
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

Summary

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.

← Episode 3Java Operators: Integer Division, %, ++, ==, &&, || and Precedence