In this chapter, you will learn ways to prevent users from unintentionally crashing your programs. The focus will be on try/catch blocks and using specific scanner methods to read certain data types and prevent exceptions from occurring.
13.1 Exceptions
Up to this point in the series, all the programs requiring user input have assumed that the user knows exactly what they’re doing and that they won’t make mistakes or typos. What happens if we ask the user to type a number and they type a letter instead? What if we ask them to select from 3 choices – 1, 2, or 3, and they accidentally enter 4? Chances are the program will crash. In production, we cannot let this happen. A program shouldn’t crash just because a user made a mistake. We need to review their input, display feedback on any issues, and ask them to try something else.
When Java encounters a preventable error, an exception is thrown. An exception is defined as any event that occurs which disrupts the regular flow of a program’s execution. We have previously discussed a few exceptions. One example from recent chapters is the IndexOutOfBounds exception, which occurs when a program tries to access a value in an array which does not exist (like trying to get the 50th element of a 5 element array).
Exceptions are similar to Errors. They both interrupt a program and may cause crashes. However, Errors show a deeper problem with the software and may result from some type of logic error on the programmer’s part. Exceptions are preventable issues usually caused by mistakes which can be corrected during runtime without entirely crashing the program. If your program runs out of system memory because you’re dealing with massive amounts of data, or you’ve created too many large objects, there’s not much the end user can do to resolve it. That will cause an OutOfMemory Error and the program will crash. If the program has a problem because a user typed the letter A instead of 1, that is an easily resolvable exception.
InputMismatchException
Consider the following code, which asks the user to enter a number and then prints out that entered number multiplied by two.
Ex. 13.1 – Multiply by Two
int x;
Scanner input = new Scanner(System.in);
System.out.println("Type a number:");
//read the next int
x = input.nextInt();
//multiply by two and close the scanner
System.out.println("x times two is: " + (x * 2));
input.close();
Code language: JavaScript (javascript)
If the user enters an int, the program executes as expected.
Type a number: 5 x times two is: 10
Now let’s see what happens if we enter something else. Like the word “apple.”
Type a number: apple Exception in thread "main" java.util.InputMismatchException at java.base/java.util.Scanner.throwFor(Scanner.java:943) at java.base/java.util.Scanner.next(Scanner.java:1598) at java.base/java.util.Scanner.nextInt(Scanner.java:2263) at java.base/java.util.Scanner.nextInt(Scanner.java:2217) at Main.main(Main.java:12)
Since the word “apple” is a String and not an int, an InputMismatchException has occurred. The input did not match the expected data type.
The easiest way to handle the above exception is to use a try/catch block.
13.2 Try/Catch Blocks
Try/Catch blocks are ways to “try” to execute code and “catch” any exceptions. It’s like telling the computer to try something, and if it fails, do this instead.
The structure of a try/catch block is as follows:
13.2a – Try/Catch Template
try{
//code to do
}
catch(Exception e){
//block of code to handle exceptions
}
finally{
//do this always when try/catch is complete
}
Code language: PHP (php)
The try block is the set of code we are trying to execute. The catch block catches the exception. It gets executed when an exception occurs. An exception is a particular type of object in Java that gets “thrown” when an issue arises. The above example catches all exceptions, but it is possible to catch specific exceptions and do different things depending on which exception was caught. The finally block is optional. It is executed at the end, regardless of whether an exception occurred.
Here is a flowchart of the execution process:
Checking user input to make sure it’s in the right format is known as input validation. Let’s change example 13.1 to catch the possible InputMismatchException. This time, it will print out a message saying the user did not enter a number, rather than showing them an Exception.
13.2b – Basic Handling
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int x;
//open scanner
Scanner input = new Scanner(System.in);
System.out.println("Type a number:");
try{
//read the number
x = input.nextInt();
//print number multiplied by two
System.out.println("x times two is: " + (x * 2));
}
catch(Exception e){
System.out.println("Something went wrong, relaunch the program to try again.");
}
finally{
System.out.println("All done!");
input.close();
}
}
}
Code language: JavaScript (javascript)
Now, when I enter a number, this happens:
Type a number: 5 x times two is: 10 All done!
And when I type something else, this happens:
Type a number: apple Something went wrong, relaunch the program to try again. All done!
People unfamiliar with Java likely won’t know what an InputMismatchException means. Now the program is a bit more understandable by an average user. We have printed a more human-readable message explaining what went wrong and how the user can correct it.
Notice that the “All done!” text was printed to the console in both scenarios, since it’s in the finally block.
Next, let’s improve the program further. Rather than ending the program when the user enters an incorrect value and asking them to restart the program, we can ask them to try again and enter the correct value without restarting the program.
The easiest way to do this will be to place the operations in a while loop. When a number is entered correctly, we break the loop. If a number is entered incorrectly, the loop repeats.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int x;
//open scanner
Scanner input = new Scanner(System.in);
while (true) {
try {
System.out.println("Type a number:");
//read the number
x = input.nextInt();
//print number multiplied by two
System.out.println("x times two is: " + (x * 2));
//we have gotten to this point without issue, we can end the loop
break;
} catch (Exception e) {
System.out.println("Something went wrong, let's try that again.");
//tell scanner to go to the next line to prevent infinite loop of scanner reading printout
input.nextLine();
//since it's a while true loop, it will just repeat until the try block executes fully
}
}
//remember to close scanner
input.close();
}
}
Code language: JavaScript (javascript)
Now, when I run the program, I can keep trying until I enter a number properly.
Type a number: banana Something went wrong, let's try that again. Type a number: muffins Something went wrong, let's try that again. Type a number: 5 x times two is: 10
Note that input.close();
came outside the try/catch block and the loop. This is to leave it open in case an exception happens and the user wants to try again.
13.3 Handling Multiple Exceptions
Next, let’s consider a program that takes two numbers as input and divides the first by the second.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
//initialize vars
int a;
int b;
Scanner input = new Scanner(System.in);
//record input
System.out.println("Enter first number:");
a = input.nextInt();
System.out.println("Enter second number:");
b = input.nextInt();
//close scanner
input.close();
//display results
int result = a / b;
System.out.println("a / b is: " + result);
}
}
Code language: JavaScript (javascript)
Like the previous example, it’s possible to get an InputMismatchException from the code above.
Enter first number: apple Exception in thread "main" java.util.InputMismatchException
Additionally, it’s possible to get an ArithmeticException if the user attempts to divide by zero (you can’t divide by zero).
Enter first number: 100 Enter second number: 0 Exception in thread "main" java.lang.ArithmeticException: / by zero at Main.main(Main.java:21)
You could handle this one of two ways. First, you could do something similar to the multiplication example. catch (Exception e)
catches all exceptions. You could generically say something went wrong and have them try again.
Instead, let’s inform the user with a message of their exact mistake. They either 1) did not enter valid ints or 2) tried to divide by zero. To do this, we will use multiple catch blocks and specifically define the exception type.
import java.util.InputMismatchException;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
//initialize vars
int a;
int b;
int result = 0;
Scanner input = new Scanner(System.in);
while (true) {
try {
//record input
System.out.println("Enter first number:");
a = input.nextInt();
System.out.println("Enter second number:");
b = input.nextInt();
//calc results
result = a / b;
//if we get here, haven't experienced an exception, can leave the loop
break;
}
//catch the ArithmeticException
catch (ArithmeticException e) {
System.out.println("Oops. Arithmetic problem - don't divide by zero. Try again.");
input.nextLine();
}
//catch the InputMismatchException
catch (InputMismatchException e) {
System.out.println("You must enter whole numbers only. No decimals, words, or other info. Try again.");
input.nextLine();
}
//catch any other possible exceptions
catch (Exception e) {
System.out.println("Something else must have gone wrong...");
//print the exception error info
e.printStackTrace();
break;
}
}
//close scanner
input.close();
//display result
System.out.println("a / b is: " + result);
}
}
Code language: JavaScript (javascript)
Now you can see, it tells the user exactly what went wrong and allows them to retry until they get the input right.
Enter first number: apple You must enter whole numbers only. No decimals, words, or other info. Try again. Enter first number: 100 Enter second number: 0 Oops. Arithmetic problem - don't divide by zero. Try again. Enter first number: 5 Enter second number: 5 a / b is: 1
Note that the last catch block catches any other exception aside from the two specified exceptions before it. If this happens, e.printStackTrace();
will print out the exact exception details and the loop will be broken.
You may also catch multiple specified exception types in one catch block using the or operator:
try {
//code to try
}
catch (ArithmeticException|InputMismatchException e){
System.out.println("Problem with arithmetic or input");
}
Code language: JavaScript (javascript)
Scanner Tip: Remember, when using the Scanner for System InputStream (System.in), only close it after your program is entirely done using it. You cannot close and re-open it if you need it later without restarting the program.
13.4 Common Exception Types
Besides the ArithmeticException and InputMismatchException, here are examples of some other common exceptions you may run into.
ArrayIndexOutOfBoundsException
The ArrayIndexOutOfBoundsException occurs when you attempt to access an element of an array that does not exist.
Prevention: Ensure your program does not access indices which do not exist. Use the array.length variable to check array size before attempting to manipulate or add additional values to it.
Example:
try{
int[] arr = new int[5];
arr[6] = 7;
}
catch (ArrayIndexOutOfBoundsException e){
System.out.println("The array only has 5 elements, you tried to access index 6.");
e.printStackTrace();
}
Code language: JavaScript (javascript)
StringIndexOutOfBoundsException
A StringIndexOutOfBoundsException occurs when you attempt to modify or access a character beyond the bounds of a given string. For example, trying to get the 50th char of a String that’s shorter than that.
Example
try{
String s = "Hello there.";
char c = s.charAt(50);
}
catch (StringIndexOutOfBoundsException e){
System.out.println("tried to get a char that's not there");
}
Code language: JavaScript (javascript)
NullPointerException
A NullPointerException occurs when the program attempts to access information from a variable reference which is pointing to nothing or a null value.
Prevention: Trace where the null value came from and ensure it’s initialized with a value prior to using.
Example
public class Main {
public static void main(String[] args) {
try{
doSomethingWithVariable(null);
}
catch (NullPointerException e){
System.out.println("x is null");
}
}
public static void doSomethingWithVariable(Integer x){
System.out.println("The value times two is: " + (x * 2));
}
}
Code language: JavaScript (javascript)
IllegalArgumentException
An IllegalArgumentException occurs when you pass an argument to a method that is invalid. It may be the right data type, but it might not make sense within the context of the method being called. The argument is “illegal”.
A BigInteger can be created by parsing a number from a string, e.g. “3.14” – if you use a string that doesn’t contain numbers, an IllegalArgumentException will be thrown.
Example
try{
//try to make a BigInteger with a string of text instead of numbers
BigInteger bigint = new BigInteger("Muffins");
}
catch (IllegalArgumentException e){
System.out.println("That's not a valid argument");
}
Code language: JavaScript (javascript)
FileNotFoundException
A FileNotFoundException occurs when a program attempts to access a file which does not exist on the file system. Usually this is because the file was spelled incorrectly, or was deleted/moved.
We will discuss files in greater detail in the next chapter.
13.5 Throwing Exceptions
In addition to catching exceptions, it’s possible to design methods which throw their own exceptions.
In Java, you may divide doubles by zero and get a result of infinity (dividing ints by zero throws an ArithmeticException).
System.out.println(100.0/0.0);
Infinity
Say, for example, that you want to create a new method to divide doubles. It will take two doubles as arguments and return the result of dividing the first by the second. The code is below:
public class Main {
public static void main(String[] args) {
System.out.println("100 divided by zero is: " + divide(100, 0));
}
public static double divide(double a, double b) {
return a / b;
}
}
Code language: PHP (php)
100 divided by zero is: Infinity
Suppose you want to change the behavior of the method so that it still divides doubles, but intentionally cannot divide by zero. We can design the method so that it throws an exception. We can select what type of exception we want to throw. In this case, an IllegalArgumentException or an ArithmeticException makes sense. The ArithmeticException may be the better choice here, since it’s more specific.
To throw this exception, you need to add the throws keyword to the method declaration and define what type of exception the method will throw.
public static double divide(double a, double b) throws ArithmeticException{
Code language: PHP (php)
Next, specify the scenario in which the exception gets thrown. In this case, if the second variable is 0, an ArithmeticException will be thrown. Throw it using the throw keyword.
public class Main {
public static void main(String[] args) {
System.out.println("100 divided by zero is: " + divide(100, 0));
}
public static double divide(double a, double b) throws ArithmeticException {
if (b == 0) {
throw new ArithmeticException();
} else {
return a / b;
}
}
}
Code language: PHP (php)
Now, when I run the program and try to divide by zero using the divide method, an exception is thrown, rather than getting the previous result of infinity.
Exception in thread "main" java.lang.ArithmeticException at Main.divide(Main.java:11) at Main.main(Main.java:4)
The exception may then be caught the same way as discussed earlier.
Conclusion/Review
You should now understand how to validate user input, check exceptions, and throw exceptions. This will be important in future chapters.
Review: Go back and retry the examples in this chapter yourself.
Assignment: The Integer.parseInt()
method can be used to “parse” or convert a number given in the form of a String into an int.
For example, the code below assigns a value of 5 to x.
int x = Integer.parseInt("5");
Code language: JavaScript (javascript)
Create a similar method called parseSingleInt which takes a single char as a parameter and returns the equivalent single-digit integer. For example: int x = parseSingleInt('5');
would set x to 5. If the user enters any other character than 0 through 9, it should return an IllegalArgumentException.
The main method should set int x to 5, add 5 to it, and print out 10 using the parseSingleInt method. Then, an exception should be thrown when y is set to the value of ‘a’. Surround the code setting y to ‘a’ in a try/catch block and catch the exception. Print out a message saying “Invalid number entered.” in the catch block.
Hint: You can do this by checking if char c is equal to ‘0’ and then return 0, ‘1’ returns 1, and so on. You may do this using if conditions or a switch. When you get through the list of all 10 digits 0 through 9, throw the exception.
public class Main {
public static void main(String[] args) {
int x = parseSingleInt('5');
x += 5;
System.out.println("This should print out the number ten: " + x);
//this should throw an exception since a is not a single number
System.out.println("Trying to set y to a");
int y = parseSingleInt('a');
}
public static int parseSingleInt(char c) throws IllegalArgumentException {
//your code here
}
}
Code language: PHP (php)
Sample output:
This should print out the number ten: 10
Trying to set y to a
Invalid number entered.