You must have seen somewhere.when we run a program in an IDE if the coding is not proper or there is some other sort of mistake e.g. accessing a file that does not exist etc. then the console shows up with highlighted exception errors.
Lets talk about those..
Exceptions
Java Exceptions
In the first two sections in this lesson, you worked with errors: compile-time errors which are violations of Java’s strict grammar, and runtime errors which are often caused by meaning one thing, but saying quite another. Such logical or semantic errors must be carefully and systematically expunged from your code.
However, runtime “errors” are not always the result of logical errors. Sometimes, runtime errors are caused by unusual–you could almost say exceptional–situations.
For instance, most of the time, when you read and write to a file, everything goes along normally. Sometimes, however, “bad things” happen; the disk may be full, for instance, or the file you want to write to may be a read-only file.
These kinds of situations are not mistakes that you’ve made in your code; instead they are unusual occurrences that you must allow for. If you just assume that everything will always go normally, your program is not very robust. Exceptional situations are often confused with error conditions, but they are a tiny bit different.
The Traditional Method
The traditional way of dealing with this kind of situation is through the use of completion codes. Every time you perform an operation that may fail, you must first check to be sure that the operation succeeded before you continue. If the operation fails, you have to decide whether to handle the failure at that point or to pass it back to the method that invoked the operation.
Here’s some psuedocode that shows the traditional method of dealing with exceptional situations. Consider the steps you need to follow to open a file, read some data, process the data, write the changed data back to the file, and finally, close the file:
Open, Read, Write, Close |
GET A FILENAME
OPEN THE FILE
IF NO ERROR OPENING THE FILE
READ SOME DATA
IF NO ERROR READING THE DATA
PROCESS THE DATA
WRITE THE DATA
IF NO ERROR WRITING THE DATA
CLOSE THE FILE
IF NO ERROR CLOSING FILE
RETURN OK
ELSE
RETURN CLOSE_ERROR
ENDIF
ELSE
RETURN WRITE_ERROR
ENDIF
ELSE
RETURN READ_ERROR
ENDIF
ELSE
RETURN FILE_OPEN_ERROR
ENDIF |
There are three things to notice about this code:
- Most of these operations, except for “PROCESS THE DATA” can fail, and so the program has to be prepared.
- It is very difficult to determine the normal course of action. The program is so taken up with what can go wrong, that it’s hard to be certain you are doing the right things in the right order.
- It is very difficult to write a library that depends upon code like this, because every function in the library has to return several different error codes.
The Exceptional Method
Using an exception mechanism, the same pseudocode looks like this:
Open, Read, Write, Close |
TRY TO DO THESE THINGS:
GET A FILENAME
OPEN THE FILE
READ SOME DATA
PROCESS THE DATA
WRITE THE DATA
CLOSE THE FILE
RETURN
IF ERROR OPENING FILE THEN ...
IF ERROR READING FILE THEN ...
IF ERROR WRITING FILE THEN ...
IF ERROR CLOSING FILE THEN ... |
Compare this code to the previous code, and you’ll immediately see that the code that uses an exception strategy:
- is shorter and easier to read.
- makes the normal logic–what you are actually trying to do with the method–its focus. In the traditional method, the error-handling often obscures the normal logic.
- allows you to handle an error or pass it back to the caller. Using exceptions, the caller is not forced to manually pass errors back up the “chain” of command. This is done automatically making it very easy to implement a centralized error-handling strategy.
Exception and Error Objects
In Java, when an exceptional situation occurs–if you try to write to a file that cannot be written to, if you try to write past the end of an array, or if you try to divide by zero, even though your mother warned you not to–Java will create one of two types of Throwable objects: an Error object or an Exception object.
It will then take that Throwable object and throw it right back up the call stack where the method was called from. Any method, anywhere along the way, can decide to deal with thatThrowable object, by catching it. [click the image to enlarge it]
Types of Exceptions
This illustration shows a small portion of Java’s exception hierarchy. [Click the image to enlarge it] As you can see, and as was previous mentioned, Throwable has two subclasses,Exception and Error.
![Image shows a small section of Java's Exception hierarchy](https://i0.wp.com/sofia.fhda.edu/gallery/java/unit07/common_exceptions_sm.gif)
Error Objects
An Error is an unusual situation, like the other exceptions, but it is the kind of situation that has no easy solution. If, for instance, the JVM throws an InternalError, there is nothing you can put in your code that will cure it.
Because of Java’s reliance on automatic memory management and garbage collection, an OutOfMemoryError is likewise fatal. And, even if you could catch the wileyUnknownError, what would you do with it after you’d caught it? When your program throws an Error object, it’s about to give up the ghost, and there’s nothing you can do about it.
Checked and Unchecked Exceptions
If you can’t do anything about the Error side of the Throwable family, how about the Exception side? The Exception class represents unusual situations that you may want to handle in your own code. Like Throwable, the Exception class is also subdivided into two branches–commonly called the checked and the unchecked exceptions.
The RuntimeException Class
Unchecked exceptions are those thrown by the Java runtime system, and are descended the RuntimeException class. These kinds of exceptional situations–accessing an element past the end of an array, for instance, or dividing by zero–represent unusual situations that you would normally prevent by careful programming.
These are called unchecked exceptions because you are not required to specifically handle these exceptions in your code if they occur. Most of the time, in fact, you will not handle them at all. Some times, however, handling one of these unchecked exceptions provides an easy way to accomplish a difficult task. Here’s an example. Type a number in theTextField shown here, and press ENTER. Now try typing a word, like “one.” What happens now?
The NumberFormatException class provides an easy way to recover when converting between Strings and ints using Integer.parseInt(). Writing the logic necessary to determine if a String contains a well-formed number is more work than manually converting the String to an int.
Instead of going to all that work, you can simply create a try block, [which you’ll learn to do in the next lesson], and catch NumberFormatException when someone types in “one hundred” instead of “100”.
Other Exceptions
To use the other exceptions you have to do two things. First, you have to put the code that may cause an exceptional situation into a “try” block. Then, you provide one or more “catch” blocks immediately following the “try” block.
If a method throws one of these checked exceptions–an exception not derived from the RuntimeException class–you must handle the exception, you can’t simply ignore it like you can with the unchecked exceptions.
Using try-catch-finally
In the last section, you learned about the different kinds of Throwable objects that are generated when an exception occurs. In this section, you’ll learn to trap those Throwableobjects and put them to work. You’ll learn:
- How to use try-catch to respond to specific errors.
- How to use the throws clause when you want to allow the Java runtime system to handle an exception for you.
- How to use try-catch-finally to make sure that necessary portions of your program are executed whether or not an exception occurs.
Using try-catch
If you are a long-time programmer, Java’s try-catch mechanism, shown here, looks kind of strange the first time you see it.
Most programming structures–loops, selection statements, method definitions–have the same basic “shape” in every programming language, even though the details might differ.
![Image illustrates the syntax of the try-catch block](https://i0.wp.com/sofia.fhda.edu/gallery/java/unit07/try_ca_sm.gif)
That’s not true with try-catch, which seems to combine elements of loops and methods together in a package that just doesn’t “look right.” Once you understand how try-catchworks, though, the strangeness goes away, and it starts to look a little bit more natural.
The try Block
The first portion of a try-catch statement is the try block. This is the easiest part to understand. A try block consists of the keyword try followed by a brace-delimited block. The braces are part of the try-catch syntax, and are required. This is different than a loop body or the body of an if statement, where the braces are optional.
Inside the braces you can put any number of statements that may throw an exception.
A try Block |
int a = 3, b = 0;
int n = 0, x = 0;
try
{
n = System.in.read();
Thread.sleep(100);
x = a / b;
} |
If you use a method that throws a checked exception–that is, an exception that is not a subclass of the RuntimeException class–then you must put the statement inside a tryblock. Common methods that throw checked exceptions include the System.in.read() method, [which throws IOException], the Thread.sleep() method, and the MediaTrackerwaitFor() methods which you’ll encounter when we start using Image objects.
The statements inside the try block are not restricted to those that may throw checked exceptions; you can place any statements you like inside the try block. If you call a method or perform an operation that generates an unchecked exception–say a NullPointerException or a NumberFormatException–then you can handle the exception by adding an appropriate catch block, which you’ll meet shortly.
You are not required to provide a catch block for the unchecked exceptions which may be generated inside your try block, but you are required to provide a catch block for eachchecked exception that might be thrown.
The catch Blocks
Immediately following your try block you must supply one or more catch blocks. The syntax for the catch blocks looks like this:
catch (<Exception1-Class> <var1>)
{
// Handle exception1 here
}
catch (<Exception2-Class> <var2>)
{
// Handle exception 2 here
} |
This is the part that gets a little tricky. Each catch block starts with the keyword catch, which is followed by parentheses. Inside the parentheses you declare an exception variablewhich is used to hold the exception object if that particular exception is thrown inside the try block.
You must provide a name for each exception object, and, although this looks like a method header, the scoping rules are somewhat different. Each exception variable used in one try-catch situation must have a unique name.
Following the exception variable declaration is a brace-delimited block where you add the actions you want to take when that particular exception is thrown. As with the try block, the braces around the catch block body are required. [Early versions of javac did not enforce this restriction, so you may still see some code that has no braces surrounding the body of the catch block].
You must provide a catch block for every checked exception that may be thrown inside your try block. Let’s continue the example we started earlier. Because you know thatSystem.in.read() throws an IOException, and that IOException is a checked exception, you can add a catch block like this:
A catch Block |
int a = 3, b = 0;
int n = 0, x = 0;
try
{
n = System.in.read();
Thread.sleep(100);
x = a / b;
}
catch (IOException ioe)
{
System.out.println("No read()");
} |
To compile this, you must import the java.io package, where IOException is defined. Once you do that, you can recompile. When you do, here’s what you’ll see:
C:\JavaOnline\unit7>javac TryCatch.java
TryCatch.java:15: Exception java.lang.InterruptedException must be caught,
or it must be declared in the throws clause of this method.
Thread.sleep(100);
^
1 error |
As you can see, the Thread.sleep() method throws an InterruptedException. This is a checked exception, so you must catch it as well. Let’s add a catch block forInterruptedException and see what happens.
A Second catch Block |
int a = 3, b = 0;
int n = 0, x = 0;
try
{
n = System.in.read();
Thread.sleep(100);
x = a / b;
}
catch (IOException ioe)
{
System.out.println("No read()");
}
catch (InterruptedException ie)
{
System.out.println("No sleep()");
} |
Because InterruptedException is part of the automatically-included java.lang package, you don’t have to add any new import statements. You must make sure that your new exception variable has a different name than the first, however, or Java will complain that a variable with that name already exists. The new variable is named ie instead of ioe like the first.
Unchecked Exceptions
Once you do that, the program compiles without error. If you put this code into a console-mode application and run it, however, this is what you’ll see:
![Console display when running TryCatch.java](https://i0.wp.com/sofia.fhda.edu/gallery/java/unit07/try-cat.gif)
As you can see, an ArtithmeticException is being thrown because we are dividing by zero. ArithmeticException is a sublcass of RuntimeException, so it is unchecked. The Java compiler does not require you to catch it, nor do you have to place the code that causes the exception inside a try block. If you move the line
x = a / b;
outside of the try-catch, the program runs just the same.
Although you don’t have to use try-catch with unchecked exceptions, you certainly can. If you add a catch block for ArithmeticException to your program, you can catch and handle the divide-by-zero exception in your own code. Generally, you don’t want to do this, because runtime exceptions usually indicate a programming error that should be fixed. For certain tasks, however, such as checking to see if a String is properly formatted as a number by using NumberFormatException, catching an unchecked exception is the smart way to go.
Exception Matching
Because the various exception classes are arranged in a hierarchy, it is possible to catch several exceptions using a single catch block. If, for instance, you add a catch block forException, the superclass for all exceptions, then your catch block will intercept every exception that can be generated. [This is not a good idea, by the way.]
![Image shows how different exception types can be caught. Click to enlarge.](https://i0.wp.com/sofia.fhda.edu/gallery/java/unit07/exception_matching_sm.gif)
You can use this hierarchy of exceptions to handle certain exceptions and to defer handling others.
When an exception occurs, the catch blocks are searched in order, looking for a match. That means, you should place your most specific catch blocks first, and the more general ones later.
If you place your general [superclass] catch blocks first, then the more specific [subclass] catch blocks will never be searched.
An Alternative to try-catch
One of the beauties of Java’s exception mechanism is its flexibility. If you decide that you don’t want to handle a particular exception, then you don’t have to: you can pass it, like a hot-potato, back to the Java runtime system, and let Java handle it. Here’s how that works.
Suppose you want to write a method for a console-mode application that reads integers from the keyboard. You want the method to return an int if it succeeds, but, if the user types in “cat” or “100”, you don’t want to be bothered correcting them. You’re happy to let Java do that.
![Image shows the use of throws Exception with a method that may throw several types of exceptions](https://i0.wp.com/sofia.fhda.edu/gallery/java/unit07/throws_sm.gif)
As you can see from the illustration [click to enlarge], there are two possible things that can go wrong inside your method. The System.in.read() method, used to read from the keyboard, can throw an IOException. Also, the Integer.parseInt() method can throw a NumberFormatException.
Correcting Figure 8-14 |
This is taken from Figure 8-14 in your book which has two errors. The method readInt() should return an int, not a String, and the Integer.parseInt() method throws a NumberFormatException, not the non-existent NumericFormatException. |
Because NumberFormatException is an unchecked exception, you don’t have to do anything to pass it on to the Java runtime. IOException is a different matter. If you try to useSystem.in.read() in your code without placing the statement inside a try–catch block, then Java will not compile your code.
You don’t have to use try–catch for IOException, however. Instead, you can defer to the caller of your method by adding “throws IOException” to the method definition. This means that any method which calls readInt() must place the call in a try–catch block, or throw the exception as well.
If you wanted to add a Thread.sleep() to the readInt() method, you would have to add the InterruptedException to your throws clause as well, like this:
public int readInt()
throws IOException, InterruptedException
{
// Code here
} |
If you don’t want to be bothered with handling any exceptions at all, however, you can simply use throws Exception, and be done with it.
Exception Strategies
When should you use try–catch and when should you rely on the throws clause? Here are some simple guidelines that might help you:
- If you know how to handle a situation, use try–catch.
- If you don’t know how to handle an error, or, if you think there may be situations where users of your code will want to handle an error differently, then use throws.
In any event, you should make sure you use exceptions for exceptional situations only. Don’t let exception handling make up for sloppy programming. You should never, for instance, rely on exception handling to tell you when you have exceeded the bounds of an array.
The finally Clause
As you’ve just seen, when an exception is thrown in a try block, program control jumps to the catch block that handles that particular exception.
Sometimes, however, this can lead to problems because code necessary for managing resources may be skipped. For instance, every time you open a file, you should close the file. Files are an operating system resource that must be manually returned to the O/S by closing the file. But, where should you put the code to close the file? Here’s an example:
A Problem with try-catch |
try
{
openFile();
readData(); // Exception thrown
closeFile(); // This is skipped
}
catch (IOException ioe)
{
// closeFile() not executed if no exception
}// closeFile() possibly executed |
As you can see, there are three possible places where the call to closeFile() can go:
- In the try block, following readData()
- In the catch block
- After the try-catch block
Each of these locations has a problem.
- If you put the code in the try block, then it will not be executed if an exception is thrown in the readData() method.
- If you put the code only in the catch block, it won’t be called unless an error occurs.
- If you put the code after the try-catch block, and the catch block terminates the program, you’ll have failed to close the file as well.
The first alternative is to put the code in multiple places; a better solution is to place the code, once, in a finally block. To fix this problem, try-catch has an optional finally clause, which will always be called.
You can use the finally clause to guard against resource depletion of items like file handles and graphic context handles [which you’ll meet in upcoming units].
![Image shows the syntax of the finally block.](https://i0.wp.com/sofia.fhda.edu/gallery/java/unit07/try_cat1.gif)