Getting User Input

Things To Do First

Things To Do Later

Input Using Scanner

Some programs require console input and console output. We already know how to do console output using the println() method and the print() method:

System.out.println("Hello, World!");
System.out.print("Hello ");
System.out.println("World!");

Recall that System is the name of a class in Java. This class allows you to get certain information about the user's system, and it also allows you access to certain system devices. System.out gives you access to the default output device, which is the monitor. Invoking the println() method on System.out causes the value in the println() brackets (the argument) to be printed on the monitor. In the example above, the argument "Hello, World!" is printed on the monitor.

There is also a device referred to as System.in. This references the default input device. On most systems, this is the keyboard. Together, the monitor and keyboard is often referred to as the console. That's why, when we do input and output using the screen and keyboard, we call it a console program. Sometimes you'll also hear it referred to as a command-line program or command-line interface, because the input and output is occurring at the command line or prompt.

There is a special class in Java called the Scanner class. So far we've been using classes like System and String. These classes contain methods that we can use (like println() and print()). The Scanner class is a different kind of class. You have to create a Scanner object in order to use the methods of the Scanner class. We do this by creating a variable, and instead of making the variable a primitive type (like int or double), we define it as "Scanner type":

Scanner input;

The variable here is called "input", and we've declared this variable to hold Scanner objects. The identifier "input" follows the same standards and conventions for any variable identifier, so remember that you can call this variable anything you like as long as it follows those same rules. For example, I could have said:

Scanner scanner;

Maybe I like the variable input better, or maybe you prefer to use scanner, instead (yes, this is acceptable, because it starts with a lower-case letter; it won't conflict with the name of the Scanner class).

Next, we have to construct the Scanner object and store it in the input variable:

input = new Scanner(System.in);

In this statement, the new Scanner() part of the statement constructs a new Scanner object. A Scanner object will read inputs for you, but it needs to know which device you want to read inputs from. We want it to read inputs from the keyboard, which is the default input device, so we tell it that we want it to use System.in. We do this by saying new Scanner(System.in).

If you prefer, you can put this all on one statement, instead:

Scanner input = new Scanner(System.in);

This statement says, "Create a new Scanner object that reads data from the keyboard, and then reference that Scanner object via the input variable."

Once you've created a Scanner object, you can use many of the methods that it contains. See the Scanner Documentation for a description of the class and list of methods you can use. Listing 2.2 and 2.3 in chapter 2.3 demonstrate how you can use the methods of the Scanner class. Type up these programs and try them yourself before moving on.

Important!
The Scanner class is not in the default java.lang package like System and String are. The Scanner class is in the java.util package. When you use the Scanner class in a program, you will need to add the statement import java.util.Scanner;
Note
Can we use import java.util.*; (wildcard imports) instead? You shouldn't. You should always import the class by it's name. It's hard to explain why because it requires more knowledge of Java than you have at this point, but perhaps you can store this away for another day when it makes a bit more sense. If it's too much, don't worry about it: it's enough to know that you shouldn't use "wildcard imports".

You shouldn't use wildcard imports because it often causes ambiguity. For example, say you wrote a class called Robot in a package/namespace called "com.foo.logic", compiled it and are now using it in another program. In that program, you decide not only do you want to use your own Robot class, but you'd like to use Java's Color class, too. Color is in the java.awt package in Java, so you might start your program with:

import com.foo.logic.*;  // so I can use my Robot
import java.awt.*;   // so I can use Color

Then, in your main() method, you add the code:

Robot myBot = new Robot();  // construct my robot
myBot.setColour(new Color(255, 0, 255));   // make my robot magenta coloured

It just so happens that the java.awt package also contains a class called Robot! So when you construct your own Robot, Java realizes Robot is not in the default package java.lang, so then it goes to check your imports to see if it's in one of those packages. It sees that you're importing both com.foo.logic and java.awt, and both of those contain a class called "Robot". Uh oh - which Robot should it choose?? It won't know which Robot you want to construct: com.foo.logic.Robot or java.awt.Robot?

If instead, you did your imports as:

import com.foo.logic.Robot;  // so I can use my Robot
import java.awt.Color;   // so I can use Color

Then Java would always know when you meant to use your Robot because it only sees you pointing to com.foo.logic.Robot, and not java.awt.Robot.

This kind of thing happens all the time: even in the Java Foundation Classes there are several classes in different packages with the same name. So it's always best to import classes by name and not use wildcard imports.

The Scanner object's methods will read in data until it reaches any "whitespace" character or characters. This includes spaces, tabs, and new-lines. One problem with the scanner class is when you want to read an entire string with spaces. Try the following program to understand the problem:

import java.util.Scanner;

public class  TryScanner {

    public static void main(String[] args) {

        Scanner input = new Scanner(System.in);
        System.out.println("Enter an integer: ");
        int num = input.nextInt();
        System.out.println("Your int: " + num);
		
        System.out.println("---------");
        System.out.println("Enter a floating-point value:");
        double num2 = input.nextDouble();
        System.out.println("Your floating-point: " + num2);
		
        System.out.println("---------");
        System.out.println("Now enter a string.");
        String str = input.nextLine();
        System.out.println(str);
    }
}

When you run the program, you'll get the following:

Enter an integer: 
23
Your int: 23
---------
Enter a floating-point value
2.5
Your floating-point: 2.5
---------
Now enter a string.

Press any key to continue . . .

When the program runs, the prompt to enter a string appears but there is no opportunity to enter anything!

What if we use the next() method instead of nextLine()? Change the last section of your code:

import java.util.Scanner;

public class  TryScanner {

    public static void main(String[] args) {

        Scanner input = new Scanner(System.in);
        System.out.println("Enter an integer: ");
        int num = input.nextInt();
        System.out.println("Your int: " + num);
		
        System.out.println("---------");
        System.out.println("Enter a floating-point value:");
        double num2 = input.nextDouble();
        System.out.println("Your floating-point: " + num2);
		
        System.out.println("---------");
        System.out.println("Now enter a string.");
        String str = input.next();
        System.out.println(str);
    }
}

This time, we get something like:

Enter an integer: 
23
Your int: 23
---------
Enter a floating-point value
2.5
Your floating-point: 2.5
---------
Now enter a string.
Hi there!  How are you?
Hi
Press any key to continue . . .

This time, we were allowed to enter a string, but only the first word in the string was saved to the variable. That's because the next() method stops "recording" at the first space.

But why didn't nextLine() work? The nextLine() method is supposed to stop recording when it sees a new-line (enter key). The problem is not actually with nextLine(). The problem is actually the previous calls to Scanner's methods.

When a user types values using the keyboard, each keystroke is stored in the input buffer. The input buffer is an area of memory that the Scanner object uses to "record" input values. Whenever you use one of the Scanner's methods, it goes to the input buffer and reads back the values stored there. As it reads a value, that value is removed from the input buffer. To see how this works, try the following:

import java.util.Scanner;

public class  TryScanner {

    public static void main(String[] args) {

        Scanner input = new Scanner(System.in);

        System.out.println("Enter an integer, then a " +
            "double, then type some text.");
        int input = keysIn.nextInt();
        double dblNum = input.nextDouble();
        String strText = input.nextLine();

        System.out.println(intNum);
        System.out.println(dblNum);
        System.out.println(strText);
    }
}

When the program runs, type:
23 4.5234 This is some other text
Then press the ENTER key. Your output should appear as:

Enter an integer, then a double, then type some text.
23 4.5234 This is some other text
23
4.5234
 This is some other text
Press any key to continue . . .

Once you enter the complete line of values, they are stored in the input buffer. When you call nextInt(), the Scanner object goes to the input buffer and reads back an integer value. That value (23) is then removed from the buffer, because it has been processed by the Scanner. When nextInt() is executing, it takes all the characters it finds until it encounters a white-space character (such as tab, space, or new-line). Then it takes those characters and parses or converts them into an int value. It does not take the white-space character that indicates the end of the int value, so that space is still in the buffer after nextInt() executes.

Note
According to the documentation for the Scanner class, methods like nextInt() and nextDouble() "first skip any input that matches the delimiter pattern.." when an input is read. In other words, when the method begins reading input, it skips over any whitespace characters and then tries to read and return a valid input. This means that when the sample string "23 4.5234" is read with a call to nextInt() and then nextDouble(), the nextInt() method will first read and return the value 23 and stop at, but not read, the space character. Then, nextDouble() will see the space, skip over it, and then try to read and return the value 4.5234. However, the nextLine() method does not work this way: it will not skip any delimiter encountered first. It will attempt to read whatever it can before it encounters a new-line character.

Then you call the nextDouble() method. The Scanner goes back to the input buffer and sees a space, and a double value terminated by the next white-space character (a space, in this case). The Scanner object understands that the first space was just a delimiter or separator that divided the previous value from the current one, so it tosses that away. Then it reads the 4.5234 as a double, stopping at the next space, and stores it in the dblNum variable. Finally, it removes the double value from the input buffer. What's now left in the input buffer is the second space, and the string "This is some other text" followed by a new-line character.

The nextLine() method is called, and the Scanner goes to the input buffer. It knows that the nextLine() method is a bit different. The other methods will stop at any whitespace because it recognizes whitespace characters as delimiters. However, the nextLine() method will read in all the values until it finds a new-line character. Therefore, the newLine() method, when called, goes to the input buffer and grabs the space and the text that comes after it. It then finds the new-line, so it knows to stop taking characters. The characters are all removed from the input buffer, and so is the new-line, although the new-line is thrown away - it is not stored as part of the rest of the string.

an input buffer containing the sample text, 23 being read and stored in intNum
1. When nextInt() is executed, it reads back the integer value and stores it in the
intNum variable. Then the integer value is removed from the input
buffer.
the input buffer, now only showing the floating point value and text; the floating point value is copied into dblNum
2. The input buffer now contains a space, a double, and some text. When
nextDouble() is executed, it knows the space is the delimiter, so the space is discarded.
Then it reads the double value and stores it in the variable dblNum. The
double value is then removed from the input buffer.
the input buffer now only contains the text and the new-line at the end, the text is copied into strText
3. Now the input buffer contains a space (the delimiter between
the double and the text), and the rest of the text ("This is some other
text"). The nextLine() method uses the new-line as the delimiter,
so it removes all the text from the input buffer and stores it in the
strText variable. It stops at the new-line. Then it takes the new-line
out of the buffer and discards it.

Now run the program again, but this time follow each input value by pressing the enter key. In other words, run the program and type:

23 [press enter]
4.5234 [press enter]
This is some other text  [press enter]

What you'll find is that after entering the double value, you are not given an opportunity to press the Enter key! This is because of the way the methods work as described above. nextInt() will take the int and stop at the first whitespace character(s), which in this case is the new-line you pressed after entering 23. Then nextDouble() executes and sees a new-line left there from the previous statement. It considers this new-line as whitespace, so it tosses it away. Then it takes the double that comes next, stopping at the 2nd new-line you pressed after entering 4.5234. It leaves this new-line in the buffer.

The nextLine() method executes next, and it sees the new-line that came after the double value. It knows it's supposed to take all data until it comes to the new-line and then quit. Well, it encountered a new-line right away, so it takes it, tosses it away, and then quits.

So what do we do to solve this problem? There are a couple of solutions. In other language, you could clear the input buffer of the new-line after you read the last numeric value. In Java, the Scanner class doesn't have a method that does this for you. Instead, you could just call the nextLine() method to toss away the new-line, then call it again to read in the line of text:

Scanner keysIn = new Scanner(System.in);

System.out.println("Enter an integer, then a " + 
    "double, then type some text.");
int intNum = input.nextInt();
double dblNum = input.nextDouble();

// toss the last new-line:
input.nextLine();

// now read the actual string:
String strText = input.nextLine();

System.out.println(intNum);
System.out.println(dblNum);
System.out.println(strText);

When you run the modified program and press enter after each input, you'll get something like:

Enter an integer, then a double, then type some text.
23
2.5
This is a line of text.
23
2.5
This is a line of text.

This works! Some programmers might not be happy with this solution, however. One alternative is to "reset" the Scanner object before you grab the line of text. To reset the Scanner object, you just redefine it using the same Scanner variable: input = new Scanner(System.in); This will also clear the input buffer of any input data that was left over:

Scanner input = new Scanner(System.in);

System.out.println("Enter an integer, then a " +
    "double, then type some text.");
int intNum = input.nextInt();
double dblNum = input.nextDouble();

// reset the scanner
input = new Scanner(System.in);
// now read the actual string:
String strText = input.nextLine();

System.out.println(intNum);
System.out.println(dblNum);
System.out.println(strText);

When you run the program, you should get the same output as the previous example.

A second alternative is to always capture your input using the nextLine() method, then you never have to worry about extra characters in the input buffer. For example:

Scanner input = new Scanner(System.in);

System.out.print("Enter an integer: ");
String strInteger = input.nextLine();
System.out.print("Enter a double: ");
String strDouble = input.nextLine();
System.out.print("Type some text: ");
String strText = input.nextLine();

System.out.println(strInteger);
System.out.println(strDouble);
System.out.println(strText);

This program works just fine. However, what if you wanted to perform calculations on your numeric values? You can't calculate with a String! In this case, we would need to convert our String values into ints and doubles.

In Java, there are some special classes called wrapper classes that are associated with each primitive type. For example, the wrapper class for the int primitive type is called Integer, and the wrapper class for the double primitive type is called Double. These wrapper classes contain methods that you can use to convert Strings into primitive types: they're called the "parse" methods. For example:

// converts strValue into an int and stores in intValue
int intValue = Integer.parseInt(strValue);
// converts strValue into a double and stores in dblValue
double dblValue = Double.parseDouble(strValue);

In the first statement, we call on the parseInt() method in the Integer class and give it strValue as an argument/input. We can assume here that strValue is a String variable. The Integer.parseInt() method then converts strValue into a primitive int value and stores that result into the variable intValue.

In the second statement, we call on the parseDouble() method in the Double class and give it strValue as an argument/input. Again, this example assumes strValue is a String variable. The Double.parseDouble() method converts strValue into a primitive double and stores that result into the variable dblValue.

You can use either of these methods to convert user-input values into the appropriate data type. For example:

Scanner input = new Scanner(System.in);

System.out.print("Enter quantity: ");
String strQty = input.nextLine();
intQty = Integer.parseInt(strQty);
System.out.print("Enter price: ");
String strPrice = input.nextLine();
dblPrice = Double.parseDouble(strPrice);
System.out.print("Enter description: ");
String strDescrip = input.nextLine();

double total = intQty * dblPrice;

System.out.println("Total for " + strDescrip + ": " 
    + total);

One thing to note about using Integer.parseInt() and Double.parseDouble() is that they will crash if they attempt to parse anything that isn't a valid int or double. For integers, this means anything that isn't a digit (so any value with letters, symbols including the decimal point and comma, or even the null-string ("") will cause the program to crash). For double values this means only digits and one decimal point are allowed; any commas, letters, symbols, multiple decimal points, and the null-string will cause the program to crash.

In a later lesson, you'll learn how to validate the user's input before you parse it, so that the program won't crash! In fact, you'll even be able to give the user a nice error message and even prompt them to try entering the value again. :)

Exercises

1. Copy the code below into a main() method of a new program, and fill in the missing code by following the instructions in the comments:

public class ScannerExercise {

    public static void main(String[] args) {
    
        // construct a scanner to get keyboard input

        
        // ask the user for a decimal number
        // (add the stmt to retrieve the value and store in an
        // appropriate variable) 
        System.out.print("Enter a decimal number: ");

        
        // calculate the number times itself (the square)
        // and store in an appropriate variable (which needs
        // to be declared - see last statement below where
        // the variable is being used) 
        
    
        // user wants to see the result, this is finished so
        // nothing to do here unless you used different variable name)
        System.out.println("Your number squared is "
            + square);
    }
}

2. Earlier you learned how to plan programs that used the Input-Processing-Output framework. Get the six IPO charts you designed earlier. For each of these, write a program that gets the user inputs using the Scanner class. Display your outputs on the console.

[solutions]