Java Programming/Throwing and Catching Exceptions
From Wikibooks, the open-content textbooks collection
Navigate Exceptions topic:
|
In Java, there are two main flow of code executions.
- Normal main sequential code execution, the program doing what it meant to accomplish
- Exception handling code execution, the main program flow was interrupted by an error or some other condition that prevent the continuation of the normal main sequential code execution. After the interruption, that is when the exception is "thrown", the search for the first matching catch block/clause begins, the search is going backward against the main flow, until a match is found.
The exception handling is built in to the language. There is a keyword to throw an exception, there is keyword to catch an exception, and there is keyword(throws) to declare that a method could throw an exception that the caller has to deal with.
An exception can be thrown from anywhere in the code by the throw keyword, plus specifying a Java object, that is instance of the Throwable class. Applications should sub-class the Exception class as an exception object to be thrown.
The following is an example of throwing an instance of the ExceptionClass.
throw new ExceptionClass("Something happened, the main program flow has to be interrupted, the caller has to be informed about this");
At the above line the current method execution is interrupted and the created exception object is thrown back to the caller. The exception object should contain the information about the reason of the interruption.
The caller of the method catches the exception by the catch keyword.
catch (ExceptionClass e) { // --- What to do with this interruption ??? --- }
Sometimes just the name of the exception class is enough to know the reason of the interruption.
Contents |
[edit] Catching Matching rules
When an exception is "thrown", the search for the first matching catch block/clause begins.
There are five main catching matching rules:
- A thrown exception object, can be caught by the
catchkeyword with specifying the exception object's class or its super-class. - When there are a list of catch clauses, it is evaluated sequentially, applying the first rule. If there is a catch, the following catch clauses are ignored.
- If there is a catch clause in the list, which will never be executed, because its super-class are listed before it, the compiler will give an error message.
- The compiler enforce that all
Exceptionand its sub-class exceptions must be handled by the programmer, except theRuntimeExceptionand its sub-classes. - If the try block would never throw an exception that is specified in the catch list, the compiler gives an error.
[edit] Rule number 1
A thrown exception object, can be caught by the catch keyword with specifying the exception object's class or its super-class.
The Throwable class is the super-class of all exception class. So specifying with the catch keyword we can catch all type of exceptions.
So the following piece of code would catch all type of exception.
catch (Throwable th) { // --- I caught all type of exception --- log_it( th ); // --- I was not suppose to catch Throwable so I throw it again --- throw th; }
There are some special exceptions that used by the JVM, those are the sub-classes of java.lang.Error. We are not suppose the catch them. So we should use the following code to catch all application, and runtime exceptions.
catch (Exception e) { // --- I caught all application and runtime exceptions --- log_it( e ); // --- I don't know how to handle this, so I throw it again --- throw e; }
[edit] Rule number 2
When there are a list of catch clauses, it is evaluated sequentially, applying the first rule, for each clause. If there is a catch, the following catch clauses are ignored.
The following piece of code demonstrates rule number 2.
The NullPointerException is caught by the first catch clause, the following catch clauses are ignored. The second catch clause will catch all RuntimeException's, except the NullPointerException, because that will be caught by the first clause. All exceptions that are defined by the application, will be caught by the last catch clause, see below.
catch (NullPointerException e) { // --- I caught a Nulpointer ex. --- log_it( e ); // --- I don't know how to handle this, so I throw it again --- throw e; } catch (RuntimeException e) { // --- I caught runtime ex. but not NullPointer --- log_it( e ); // --- I don't know how to handle this, so I throw it again --- throw e; } catch (Exception e) { // --- I caught all application but not Runtime exceptions --- log_it( e ); // --- I don't know how to handle this, so I throw it again --- throw e; }
[edit] Rule number 3
If there is a catch clause in the list which will never be executed, because its super-class are listed before it, the compiler will give an error message.
The following piece of code will not compile, it will give an error message saying that the last catch clause will never be executed. This demonstrates that the exception handling is built into the language. The compiler checks the list of catch clauses and reports an error if class follows any of it super-class on the list.
catch (NullPointerException e) { // --- I caught a Nullpointer ex. --- log_it( e ); // --- I don't know how to handle this, so I throw it again --- throw e; } catch (Exception e) { // --- I caught all application but not Runtime exceptions --- log_it( e ); // --- I don't know how to handle this, so I throw it again --- throw e; } catch (RuntimeException e) { // -- COMPILATION ERROR, THIS CODE WILL NEVER BE EXECUTED --- // --- I caught runtime ex. but not NullPointer --- log_it( e ); // --- I don't know how to handle this, so I throw it again --- throw e; }
[edit] Rule number 4
The compiler enforce that all Exception and its sub-class exceptions must be handled by the programmer, except the RuntimeException and its sub-classes.
From the application's point of view there are two types of exceptions. One is called RuntimeException, that suppose to be thrown when there is an anticipated bug in the code. For example, if the program tries to access an array, with a number that is out side of the array size, then a RuntimeException is thrown. There are many other possibilities which indicate a coding bug.
The other type of exception is called the application exception. During application design a list of possible exception is defined that can anticipated during executing the business logic code. For example, the application tries to retrieve a customer, but the customer does not exist. This may not necessarily be a bug. In this case an application exception should be thrown. Application exceptions are sub-classes of the Exception class.
The java language enforces that all application exceptions are dealt with by the application programmer.
If a method throws an application exception, that must be declared in the method signature by the throws keyword. The caller of that method can either catch the exception by a catch block or it can make sure that it is being declared to be thrown in the current method, and so on. The search for a catch block goes backward on the methods track trace, until a match is found. The compiler ensures that someone has to handle the exception.
The following method can throw a CustomerNotFoundException, so it must declare it at the method signature.
public String method() throws CustomerNotFoundException { ... throw new CustomerNotFoundException(); ... }
[edit] Rule number 5
If the try block would never throw an exception that is specified in the catch list, the compiler gives an error.
The following code would not compile because inside the try block no Exception is thrown.
try { ... } catch ( Exception e ) { }
The above code won't compile, because the try block does not throw exception. The compiler can be fooled with the following code.
try { if ( 1 == 0 ) throw new Exception(); ... } catch ( Exception e ) { }
The above code will compile now.
[edit] Example of handling exceptions
Let's examine the following code:
public void methodA() throws SomeException, AnotherException { //methodbody } public void methodB() throws CustomException { //Methodbody } public void methodC() { methodB(); methodA(); }
In the code sample, methodC is invalid. Because methodA and methodB pass (or throw) exceptions, methodC must be prepared to handle them. This can be handled in two ways: a try - catch block, which will handle the exception within the method and a throws clause which would in turn throw the exception to the caller to handle. The above example will cause a compilation error, as Java is very strict about exception handling. So the programmer forced to handle any possible error condition at some point.
A method can do two things with an exception. Ask the calling method to handle it by the throws declaration. Or handle the exception inside the method by the try-catch block.
To construct a throws declaration, add throws ExceptionName (additional exceptions can be added with commas). To construct a try - catch block, use the following syntax
... try { //Possibly exception-causing code } catch (TheException e) { //Handle the exception } finally { //Optional. Executes regardless of exceptions thrown }
The original code can be modified to work correctly in multiple ways. For example, the following:
public void methodC() throws CustomException, SomeException { try}} { methodB(); } catch (AnotherException e) { //handle it } methodA(); }
The AnotherException from methodB will be handled locally, while CustomException and SomeException will be thrown to the caller to handle it.
[edit] Application Exceptions
Application Exception classes should extend the java.lang.Exception class. Some of the JDK classes also throw exception objects inherited from java.lang.Exception. If any of those Exception object is thrown, it must be caught by the application some point, by a catch-block. The compiler will enforce that there is a catch-block associated with an exception thrown, if the thrown exception object is inherited from java.lang.Exception and it is not the java.lang.RuntimeException or its inherited objects. However, java.lang.RuntimeException or its inherited objects, can be caught by the application, but that is not enforced by the compiler.
Lets see what is the catching criteria for a catch block to catch the "thrown" exception.
A catch-block will "catch" a thrown exception if and only if:
- the thrown exception object is the same as the exception object specified by the catch-block
- the thrown exception object is the subtype of the exception object specified by the catch-block
try{thrownewException( "This will be caught below" ); }catch( Exception e ) { // --- The "thrown" object is the same what is specified at the catch-block -- }
try{thrownewNullPointerException( "This will be caught below" ); }catch( Exception e ) { // --- NullPointerException is subclass of the Exception class -- }
There can be more than one catch-block for a try-block. The catching blocks evaluated sequentially one by one. If a catch-block catch the exception, the others will not be evaluated.
Example:
try{thrownewNullPointerException( "This will be caught below" ); }catch( Exception e ) { // --- The above NullPointerException will catched by here -- }catch(NullPointerException e) { // --- THIS CODE IS NEVER EXECUTED - Compiler error // --- }
Because NullPointerException is subclass of the Exception class. All NullPointerExceptions will be caught by the first catch-block.
Instead the above code should be rewritten as follows:
try{thrownewNullPointerException( "This will be caught below" ); }catch( NullPointerException e ) { // --- The above NullPointerException will caught here --- }catch( Exception e ) { // --- Any other exception except the NullPointerException will be caught here -- }
[edit] Runtime Exceptions
The java.lang.RuntimeException exception class is inherited from java.lang.Exception. It is a special exception class, because catching this exception class or its subclasses are not enforced by the Java compiler.
- runtime exception
- Runtime exceptions are usually caused by data errors, like arithmetic overflow, divide by zero, ... . Runtime exceptions are not business related exceptions. In a well debugged code, runtime exceptions should not occur. Runtime exceptions should only be used in the case that the exception could be thrown by and only by something hard-coded into the program. These should not be able to be triggered by the software's user(s).
[edit] NullPointerException
NullPointerException is a RuntimeException. In Java, a special null can be assigned to an object reference. NullPointerException is thrown when an application attempts to use an object reference, having the null value. These include:
- Calling an instance method on the object referred by a null reference.
- Accessing or modifying an instance field of the object referred by a null reference.
- If the reference type is an array type, taking the length of a null reference.
- If the reference type is an array type, accessing or modifying the slots of a null reference.
- If the reference type is a subtype of Throwable, throwing a null reference.
Applications should throw instances of this class to indicate other illegal uses of the null object.
Objectobj =null; ... obj.toString(); // --- This will throw a NullPointerException ---
The above code shows one of the pitfall of Java, and the most common source of bugs. No object is created and the compiler does not detect it. NullPointerException is one of the most common exceptions thrown in Java.
- why do we need
null?
The reason we need it is because many times we need to create an object reference, before the object itself is created. Object references cannot exist without a value, so we assign the null value to it.
publicCustomer getCustomer() { Customer customer =null;try{ ... customer = createCustomer(); ... }catch( Exception e) { ... }returncustomer; }
In the above code we want to create the Customer inside the try-block, but we also want to return the object reference to the caller, so we need to create the object reference outside of the try-block, because of the scoping rule in Java. This is one of the pitfall of Java.
[edit] Main Exception Classes
|