User Interaction

  • Core Java: Volume I—Fundamentals

    • Chapter 3.7

Reading Input

Your programs would get pretty dull pretty quickly without a little user interaction. First, the focus will be on textual input via the console. Later, that focus will shift towards creating graphical interfaces with Java.

Importing and Initializing

To read user input from the keyboard, you're going to use something called a Scanner. This is one of several built-in classes that allows you to interact with users via the console. Although it is built into the language, you need to inform the compiler that you'll be using this class (and also where it is located). This is true of most built-in classes you'll use (more specifically, any class not defined in the java.lang package).

import java.util.Scanner;    // this is called an import statement

Import statements go at the top of the source file, above the class declaration. You can always Google a Java class to find its import statement. Once imported, you can declare and initialize a variable whose data type is Scanner.

UserInput.java
import java.util.Scanner;

public class UserInput {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
    }
}

The declaration piece follows the same dataType variableName convention you've seen. The initialization piece looks a little different, and is reminiscent of the String constructor (i.e., it uses the new operator). Every class has a constructor designed to create instances of it, and Scanner is no exception.

To create an instance of a Scanner, you need to supply a single piece of information: the source of the input to be read. In this example, the goal is to read from the standard system input (i.e., the keyboard). Java knows this as System.in, so that's what you put inside the parentheses of the constructor.

Available Methods

Like the String class, there are a number of methods available on your Scanner object. For now, you should focus on the next methods, which will wait for the user to enter a value of a certain data type.

Method

Description

Usage

nextByte

Scans the next token of the input as a byte.

byte digit = in.nextByte();

nextShort

Scans the next token of the input as a short.

short grade = in.nextShort();

nextInt

Scans the next token of the input as an int.

int age = in.nextInt();

nextLong

Scans the next token of the input as a long.

long population = in.nextLong();

nextFloat

Scans the next token of the input as a float.

float cost = in.nextFloat();

nextDouble

Scans the next token of the input as a double.

double price = in.nextDouble();

nextBoolean

Scans the next token of the input as a boolean.

boolean valid = in.nextBoolean();

next

Finds and returns the next complete token from this scanner.

String word = in.next();

nextLine

Advances this scanner past the current line and returns the line that was skipped.

String line = in.nextLine();

You're probably wondering what the repeated references to token are. The Scanner breaks up user input into chunks called tokens. By default, a token is everything between two whitespace characters (i.e., all the words in a sentence are individual tokens because they're separated by spaces).

The descriptions for next and nextLine can be a bit confusing. These come directly from the Oracle documentation, so they are a bit technical. Let's see if we can simplify it a bit. Consider the following text.

"Welcome to AP Computer Science A!"

If you used next to read this line, it would return "Welcome". It just grabs the next word, where a word is defined as a sequence of characters. The end of the word is whenever the Scanner encounters whitespace (a space, tab, line break, etc.). The nextLine method would grab everything — "Welcome to AP Computer Science A!". The end of a line is whenever the Scanner encounters a line break.

Now, you can add some prompts and start to work your way towards more interactive programs.

UserInput.java
import java.util.Scanner;

public class UserInput {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        System.out.println("How old are you?");
        int age = in.nextInt();
        System.out.println("You are " + age + " year(s) old.");

        in.close();
    }
}

This program will ask the user to enter his or her age, then print a message using the value entered. Go ahead and give it a try.

$ java UserInput
How old are you?
17
You are 17 year(s) old.

When you're done using a Scanner, it's important that you close it (see the call to close on Line 11?). The JVM manages your program's memory, but not its resources. You must release those manually.

Line 8 makes a call to nextInt and stores its result in an int. This is fine for now, but you really can't assume that users will enter the correct and expected data type. A mismatch in data types here would crash our program.

$ java UserInput
How old are you?
APCS
Exception in thread "main" java.util.InputMismatchException
    at java.base/java.util.Scanner.throwFor(Scanner.java:939)
    at java.base/java.util.Scanner.next(Scanner.java:1594)
    at java.base/java.util.Scanner.nextInt(Scanner.java:2258)
    at java.base/java.util.Scanner.nextInt(Scanner.java:2212)
    at UserInput.main(UserInput.java:8)

Special Cases

There is no method for reading a char. To do that, you need to use a combination of Scanner and String methods. First, read in a single token using the next method. Then, use the charAt method to grab the first character.

String word = in.next();
char letter = word.charAt(0);    // get the first character (indexes start
                                 // at 0, remember?)

You can also chain methods together to keep this on one line.

String word = in.next().charAt(0);    // same as above

Scanners can behave oddly when switching between nextLine, and next or next<DataType> methods. The newLine method consumes the line break (called a newline in Java) at the end of the input, but the next and next<DataType> methods do not.

When switching between these methods, it can sometimes appear that the Scanner is skipping over some input entirely. The Scanner is actually encountering the dangling newline left behind by the next or next<DataType> methods, and thinks it has reached the end of the input.

UserInput.java
import java.util.Scanner;

public class UserInput {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        System.out.println("How old are you?");
        int age = in.nextInt();

        System.out.println("What's your name?");
        String name = in.nextLine();

        System.out.println(name + " is " + age + " year(s) old.");
        in.close();
    }
}

The program seems correct at first glance, but try running it. You might be surprised by the output.

$ java UserInput
How old are you?
17
What is your name?
 is 17 year(s) old.

There's a dangling newline left from the call to nextInt that interferes with the second prompt. We can add a call to nextLine to consume it and fix the problem.

UserInput.java
import java.util.Scanner;

public class UserInput {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        System.out.println("How old are you?");
        int age = in.nextInt();
        in.nextLine();    // consume dangling newline

        System.out.println("What's your name?");
        String name = in.nextLine();

        System.out.println(name + " is " + age + " year(s) old.");
        in.close();
    }
}

Re-compile and re-run the program. All is well now.

$ java UserInput
How old are you?
17
What is your name?
Anthony
Anthony is 17 year(s) old.

Formatting Output

You've done some printing already, and each time you've used println. This prints the text to the console, and then advances the cursor to the next line. There is an equivalent method called print that prints text, but does not advance the cursor to the next line. This time, the focus will be on a third variant: printf. This allows you to print text, while also adding custom formatting.

Specifiers

There are a number of format specifiers that can be used to alter how text is printed to the console. Here's why this might be needed.

double x = 10000.0 / 3.0;
System.out.print(x);

Because Java prints the maximum number of non-zero digits for that data type, this will print the following.

3333.3333333333335

What if you're trying to work with currencies? You'd want to limit the number to two decimal places.

System.out.printf("%.2f", x);

This tells the printf method to limit the width of the entire value to 8 characters (which, in this example, would include the decimal point), and allow for only two digits after the decimal point. Now, it neatly prints 3333.33. As a small aside, there are better ways to work with currencies than using doubles. We'll cover those in the Bank Account Walkthrough.

There are a host of format specifiers available to us. Here are the more commonly used ones.

Conversion Character

Type

d

Decimal integer.

f

Fixed-point floating point number.

s

String.

c

Character.

b

Boolean.

%

The percent symbol.

n

Platform-depending line separator.

Flags

In addition to format specifiers, you can use flags to further customize the output. Remember the original example? You were able to format the number from 3333.3333333333335 to 3333.33. You can take this even further.

System.out.printf("%,.2f", x);    // see the added comma after the % sign?

Now, you're asking printf to format the number with separating commas. It results in 3,333.33.

Again, there are several flag options available to us.

Flag

Purpose

+

Prints a sign for positive and negative numbers.

space

Adds a space before positive numbers.

0

Adds leading zeroes.

-

Left-justifies the field.

(

Encloses negative numbers in parentheses.

,

Adds group separators.

#

Always includes a decimal point.

Hopefully you're starting to pick up on the pattern. You're going to do a lot of programming in this course!

Problem Set 3Problem Set 4

Last updated

Was this helpful?