Exceptions

Java has a mechanism to handle unexpected errors called exceptions. We have encountered this a little already. If you remember in the chapter on the if / else statement, we found that if we entered a non-number when a number was expected, the program generated an error and terminated. Also, in the chapter on the switch statement, we had to add a throws IOException declaration when we defined our main() in order to call the System.in.read() function.

When an error is detected, java can handle the error by throwing an exception. This tells the system that the error has occurred and allows other parts of the program to trap and handle the error. To introduce code to handle exceptions, you use the try / catch statement which has the following form.

try
{
   ...
}
catch (ExceptionType ex)
{
   ...
}

To see how this works, let’s go back to the program we wrote which asks for your age and then prints it out:

import java.util.Scanner;

public class HelloWorld 
{
	public static void main(String[] args) 
	{
		Scanner input = new Scanner(System.in);
		int age;
		
		System.out.println("Enter your age");
		age = input.nextInt();
		System.out.println(String.format("Your age is %d", age));
		
		input.close();
	}
}

Now if we run this program and type in something other than a number, we will get the following result:

Enter your age
xxx
Exception in thread "main" java.util.InputMismatchException
	at java.util.Scanner.throwFor(Unknown Source)
	at java.util.Scanner.next(Unknown Source)
	at java.util.Scanner.nextInt(Unknown Source)
	at java.util.Scanner.nextInt(Unknown Source)
	at HelloWorld.main(HelloWorld.java:11)

Now we could fix this by using the hasNextInt() function like we did before, but instead we are going to create a handler for the exception that is being thrown.  It looks something like:

import java.util.InputMismatchException;
import java.util.Scanner;

public class HelloWorld 
{
	public static void main(String[] args) 
	{
		Scanner input = new Scanner(System.in);
		int age;
		
		System.out.println("Enter your age");
		
		try
		{
			age = input.nextInt();
			System.out.println(String.format("Your age is %d", age));
		}
		catch (InputMismatchException ex)
		{
			System.out.println("You did not enter a number");
		}
		
		input.close();
	}
}

What we have done is surround the call to nextInt() with a try statement. Now if we enter a number like we are supposed to, then nextInt() will return that number and the following System.out.println(…) call will print it out. However, if we enter something other than a number, then the nextInt() function will throw an InputMismatchException. When that happens, the code following the nextInt() call will not be executed. Instead, execution will resume with the first line of the catch block and we will print out that they did not enter a number.

Try it out.

Now some function such as nextInt() silently throw exceptions as we have seen. However, it is possible for a function to advertise that it will throw certain exceptions. The System.in.read() function is an example of this. Looking at the documentation we see that this function advertises that it throws IOException’. When you try and call a function that throws an exception, you have two choices. You either have to handle the exception yourself, or you need to explicitly say that you are going to ignore it. If you remember, in our chapter on the switch statement, we changed the main() declaration as follows:

	public static void main(String[] args) throws IOException 

Adding the ‘throws IOException’ tells Java that this function is not going to handle the IOException, and that, if one should occur, the exception should be passed back to the calling function.

We could, of course, have chosen to handle the exception instead of passing it on to the caller. The following code illustrates how we might have done this.

import java.io.IOException;

public class HelloWorld 
{
	public static void main(String[] args) 
	{
		char ch;
		boolean	run = true;
		
		System.out.println("Type a letter");
		while (run)
		{
			try
			{
				ch = (char) System.in.read();
				
				switch (ch)
				{
				case 'A':
				case 'a':
					System.out.println("Apple");
					break;
					
				case 'B':
				case 'b':
					System.out.println("Banana");
					break;
					
				case 'C':
				case 'c':
					System.out.println("Cherry");
					break;
					
				case 'D':
				case 'd':
					System.out.println("Date");
					break;
					
				case 'E':
				case 'e':
					System.out.println("Elderberry");
					break;
					
				case 'Q':
				case 'q':
					run = false;
					break;
				}
			}
			catch (IOException ex)
			{
				run	= false;
			}
		}
		System.out.println("Done!");
	}
}

When we handle the IOException we need to terminate the loop. This is because when this exception is thrown, no more input will ever be available which means that if we call the read() function again, it will simply throw the same exception. Of course we already have a way of ending the loop by simply setting run to false.