Wednesday 16 March 2016

The Java Language: Exception Handling

The try/catch guarding statements wrap a block of code and catch designated types of exceptions that occur within it:

 try {  
 readFromFile("foo");  
 ...  
 }  
 catch ( Exception e ) {  
 // Handle error  
 System.out.println( "Exception while reading file: " + e );  
 ...  
 }  
In this example, exceptions that occur within the body of the try portion of the statement are directed to the catch clause for possible handling. The catch clause acts like a method; it specifies as an argument the type of exception it wants to handle and if it’s invoked, it receives the Exception object as an argument. Here, we receive the object in the variable e and print it along with a message. A try statement can have multiple catch clauses that specify different types (subclasses) of Exception:
 try {  
 readFromFile("foo");  
 ...  
 }  
 catch ( FileNotFoundException e ) {  
 // Handle file not found  
 ...  
 }  
 catch ( IOException e ) {  
 // Handle read error  
 ...  
 }  
 catch ( Exception e ) {  
 // Handle all other errors  
 ...  
 }  
The catch clauses are evaluated in order, and the first assignable match is taken. At most, one catch clause is executed, which means that the exceptions should be listed from most to least specific. In the previous example, we anticipate that the hypothetical readFromFile() can throw two different kinds of exceptions: one for a file not found and another for a more general read error. In the preceding example, FileNotFoundEx ception is a subclass of IOException, so if the first catch clause were not there, the exception would be caught by the second in this case. Similarly, any subclass of Exception is assignable to the parent type Exception, so the third catch clause would catch anything passed by the first two. It acts here like the default clause in a switch statement and handles any remaining possibilities. We’ve shown it here for completeness, but in general you want to be as specific as possible in the exception types you catch. One beauty of the try/catch scheme is that any statement in the try block can assume that all previous statements in the block succeeded. A problem won’t arise suddenly because a programmer forgot to check the return value from a method. If an earlier statement fails, execution jumps immediately to the catch clause; later statements are never executed. In Java 7, there is an alternative to using multiple catch clauses, and that is to handle multiple discrete exception types in a single catch clause using the “|” or syntax:
 try {  
 // read from network...  
 // write to file..  
 catch ( ZipException | SSLException e ) {  
 logException( e );  
 }  
Using this “|” or syntax, we receive both types of exception in the same catch clause. So, what is the actual type of the e variable that we are passing to our log method? (What can we do with it?) In this case, it will be neither ZipException nor SSLException but IOException, which is the two exceptions’ nearest common ancestor (the closest parent class type to which they are both assignable). In many cases, the nearest common type among the two or more argument exception types may simply be Exception, the parent of all exception types. The difference between catching these discrete exception types with a multiple-type catch clause and simply catching the common parent exception type is that we are limiting our catch to only these specifically enumerated exception types and we will not catch all the other IOException types, as would be the alternative in this case. The combination of multiple-type catch and ordering your catch clauses from most specific to most broad (“narrow” to “wide”) types gives you great flexibility to structure your catch clauses to consolidate handling logic where it is appropriate and to not repeat code. There are more nuances to this feature, and we will return to it after we have discussed “throwing” and “rethrowing” exceptions.

0 comments:

Post a Comment