The exception handling features in the Java language provide a mechanism for gracefully recovering from a wide variety of unexpected situations in your code.
Some methods handle error conditions by returning an error code. For example,
exists() method of the java.io.File class returns false if the file does not exist. However, this isn't good enough for us.
What if the method already returns something? Returning an error code may not make sense here.
What if we want to deal with the error differently depending on where we are in our program? For example, suppose we have a String that we would like to convert into an int. Even if we could figure out a way to return both the int value and a status flag that indicated success or failure, we may not know how to deal with the error quite yet… more on this later.
An exception represents a condition in which something unexpected/abnormal has occurred.
This condition may occur during the normal execution of a program, e.g.,
int x=Integer.parseInt("1.234");
When an exception occurs, the normal flow of the program is terminated.
Normal program flow is terminated by throwing and exception.
Once a exception has been thrown, program flow works backwards through the various method calls currently on the stack until the exception is caught.
An exception is caught by an exception handling routine.
We can provide exception handling routines or not.
If no exception handling routines are provided, the Java Virtual Machine will catch and handle the exception.
In order to catch an exception, we need to be watching for an exception to be thrown.
We watch for exceptions using a try block.
Consider the following code snippet:
String input = JOptionPane.showInputDialog(null, "How old are you (in years)");
int age;
try {
age = Integer.parseInt(input);
JOptionPane.showMessageDialog(null, "I'm guessing you'll be " + (age+1) + " next year");
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null, "Error! You should enter an integer value");
}
If we enter something other than an integer, the program will display the error message, otherwise it will “guess” how old the user will be next year.
To summarize…
Code between curly braces following a try statement is part of what we call a try block.
If, at any time, an exception is throw while we are in the try block, execution of the code within the try block is immediately halted. Program flow is transferred to the end of the try block.
Note: an exception can be encountered either by an explicit throw command within the try block or as a result of an un-handled exception thrown by a method which was called within the try block. In the above example, the exception was thrown by the parseInt method and was left unhandled.
Code between curly braces following a catch statement is part of what we call a catch block.
A catch block is executed if
an exception has been encountered in the try block immediately proceeding it and
the type of exception encountered matches the type of exception being caught.
The type of exception a catch block catches is specified in parentheses after the catch statement. In the above example, the catch block catches
NumberFormatException type exceptions.
Only the first matching catch block after a try block will be executed.
If no exceptions were encountered during the execution of a try block, the catch block(s) after the try block are ignored. Program flow continues with the statement following the try-catch statement.
If an exception is encountered, but no matching catch block is present, program control reverts to the calling method.
We will discuss subclasses more in the future, but, in short, a subclass is a specialization of a class. By way of analogy, a Dog is a type of animal.
Dog is not a particular animal (much like a class is not a particular object).
Spot is a specific instance of an animal of type Dog (much like an object is a particular instance of a class).
A Golden Retriever is a special type of Dog.
If Spot is a Golden Retriever, then Spot is a particular type (or subclass) of Dog.
Instances of Golden Retrievers share the the characteristics that all Dog instances share; however, they may have particular constraints on some of these characteristics.
For example, the set of potential colors that a Golden Retriever may be is more limited than the set of potential colors that a Dog may be.
Consider the following code:
String input = JOptionPane.showInputDialog(null, "How old are you (in years)");
int age;
try {
age = Integer.parseInt(input);
JOptionPane.showMessageDialog(null, "I'm guessing you'll be " + (age+1) + " next year");
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null, "Error! You should enter an integer value");
} catch (RuntimeException e) {
JOptionPane.showMessageDialog(null, "Error! Some runtime exception other than NumberFormatException was thrown");
JOptionPane.showMessageDialog(null, "Hint: " + e.getMessage());
return;
}
JOptionPane.showMessageDialog(null, "No worries. Either way we'll continue on with our program");
Recall that, if no exception occurs, all of the code except for the catch blocks will be executed.
If an exception is thrown while in the try block,
In addition to try and catch blocks, we have a finally block.
The finally block should contain code that must be executed regardless of whether an exception is thrown (or even if the try and/or catch blocks contain return statements).
String input = JOptionPane.showInputDialog(null, "How old are you (in years)");
int age;
try {
age = Integer.parseInt(input);
JOptionPane.showMessageDialog(null, "I'm guessing you'll be " + (age+1) + " next year");
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null, "Error! You should enter an integer value");
} catch (RuntimeException e) {
JOptionPane.showMessageDialog(null, "Error! Some runtime exception other than NumberFormatException was thrown");
JOptionPane.showMessageDialog(null, "Hint: " + e.getMessage());
return;
} finally {
JOptionPane.showMessageDialog(null, "I really want you to see this.");
}
JOptionPane.showMessageDialog(null, "No worries. Either way we'll continue on with our program");
throw new Exception("Info about the exception");
Modifying the previous code to throw an exception if the user entered an age greater than 120 would look like this:
String input = JOptionPane.showInputDialog(null, "How old are you (in years)");
int age;
try {
age = Integer.parseInt(input);
if(age>120)
{
throw new Exception("Out of bounds");
}
JOptionPane.showMessageDialog(null, "I'm guessing you'll be " + (age+1) + " next year");
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(null, "Error! You should enter an integer value");
} catch (RuntimeException e) {
JOptionPane.showMessageDialog(null, "Error! Some runtime exception other than NumberFormatException was thrown");
JOptionPane.showMessageDialog(null, "Hint: " + e.getMessage());
return;
} finally {
JOptionPane.showMessageDialog(null, "I really want you to see this.");
}
JOptionPane.showMessageDialog(null, "No worries. Either way we'll continue on with our program");
Some exceptions are not allowed to propagate back to the VM, i.e., they must be caught by your code.
An checked exception is an exception that is checked at compile time.
Objects from the
RuntimeException or one of its subclasses are
unchecked exceptions.
-
In order to propagate a checked exception, the method propagating the exception must explicitly indicate that it may throw a checked exception.
To indicate that a method may throw a checked exception, the method's header must include a list of checked exceptions that it may throw.
The syntax makes use of the throws keyword as follows:
void someMethod() throws IOException {
// ...
}