The term exception means "exceptional condition" and is an occurence that alters the normal program flow. A bunch of things can lead to exceptions, including hardware failures, resource exhaustion and good old bugs. When an exceptional event occurs in Java, an exception is said to be thrown. The code that handles the exception is called the exception handler and it catches the thrown exception. Exception handling works by transferring the execution of a program to an appropriate exeception handler which knows how to deal with the exception.
Exception handling should be used
Advantages of error-handling are
Java added a number of features regarding exceptions in later versions (>7)
Differentiate among checked, unchecked exceptions, and errors
All exception classes are subtypes of class Exception, this class derives from the class throwable. The figure below shows the exception hierarchy for the eception class.
As seen above there are two subclasses that derive from Throwable, Exception and Error.
Error Class | represents unusual situations that are not caused by program errors or anything that would normally happen during program execution, such as JVM running out of memory. Generally your program won't be able to recover from this type of Error, so you're not required to handle them. The compiler will not complain if you do not catch these types of errors. Technically Errors are not exceptions as they do not derive from the Exception class. |
Exception Class | represents something that happens not as a result of a programming error, but rather because some resource is not available or some other condition required for correct execution is not present. For example if you application is supposed to communicate with another application or computer that is not answering, this is an exception that is not caused by a bug. |
When an error happens the method where the error occurred creates a special object called an exception object, this get handed off to the runtime system, the exception object contains information about the error and the state of the program when the error occurred, all this is known as throwing an exception, you can also manually throw an exception.
Once an exception has been thrown, the JVM then trys to handle the exception (catch), this means that there is code (exception handler) that identifies itself as responsible for responding to the error condition that occurred. The exception may travel up the call stack in order to find the exception handler. The call stack is a listing of program counter addresses (PCs) representing instructions (method calls) from within the program which identifies the path, the application executed to get to the current instruction or statement. If no handler is found the thread that created the error or exception dies.
Create try-catch blocks and determine how exceptions alter program flow
There are three keywords that handle a basic exception
Exception Keywords |
|
try | is used to define a block of code in which the exception may occur. This block of code is called a guarded region (which means risky code goes here). A try block has to have either one of the following
The order must be catch block/s then finally block |
catch | catch clauses match a specific exception (or class of exceptions) to a block of code that handles it. Note that if there are multiple catch blocks the error is only handled by the must specific catch block, other catch blocks are then ignored. A catch clause is not required for unchecked exceptions but is required for check exceptions. if you add a catch clause for a check exception that is never thrown from the code in the try block will clause a compile error. An exception parameter is not final in a single exception clause but it is final if it is in a multiple clause. |
finally (optional) | A finally block encloses code that will always be executed whether the an exception was thrown or not. This block of code can be useful if you want to tidy up after you have tried your risky code for an example you can closed down any network sockets, database links, etc. You can have only one finally block for a try statement and it must be after the catch blocks if there are any. |
Exception Example |
|
defination | try { // your risky code goes here , could be one line or many lines of code // remember this is know as the guarded region } catch (FirstExceptionType e1) { // your code handles the specific exception here } catch (SecondExceptionType | ThirdExceptionType e2) { // your code handles the specific exceptions here, notice we can have multiple exceptions (multi-catch) } finally { // This code will always always execute even if an exception was not thrown, unless // the JVM aborts or System.exit() method is called } Note: that the exception variable is marked as final (in a multi-clause catch) and thus you cannot assign anything to it, a compiler error will occur if you do. Note: If you throw an exception in a finally block regardless of other exceptions this will be the one that is thrown, all others are disreguarded |
Try-Catch example with exception hierarchy | public class TryCatchExamples { public static void main(String[] args) { try { System.out.println("Statement 1 is just fine"); System.out.println("Statement 2 will cause the error " + (2/0)); System.out.println("Statement 3 is just fine"); } catch (Throwable t) { t.printStackTrace(System.out); printErrorStructure(t); } } // This method will just print the hierarchy of the exception public static void printErrorStructure(Object o) { Class parent = o.getClass(); String prefix = ""; System.out.println("Error caught was: "); do { System.out.println(prefix + " " + parent.getName()); prefix += "--"; parent = parent.getSuperclass(); if (parent == null) break; } while (parent.getSuperclass() != null); } } |
Java provides many exception classes, most of which have very descriptive names, to get information about a exception class you use the exception object itself as all exception objects are derived from the Throwable object the method printStackTrace() is inherited which provides useful information about the object. The printStackTrace() method prints the name of each method of the calling stack from the top, also a another helpful for debugging is the getMessage() method which returns the detail message string of this throwable.
Some exception classes can catch multiple conditions for an example the class IndexOutOfBoundsException has two subclasses, ArrayIndexOutOfBoundsException and StringIndexOutOfBoundsException. You may want to write one exception handler that deals with exceptions produced by either type of boundary error but you might not be concerned with which exception you actually have, of cause you can abuse this by using the Exception class to catch eveything which is considered bad programming.
catch more than one type of exception | try { Note: both ArrayIndexOutOfBoundsException and StringIndexOutOfBoundsException will be caught by the catch statement. |
Not advised (catch-all) | try { Note: this defeats the design objective as this could handle everything thrown at it |
try-catch in a static initializer | class StaticTest { public static String currentMessage; // Initialized to 0 public static int currentVal; // Static Initializer static { System.out.println("Initializing class StaticTest"); try { // We force an error for demonstration purposes if ((10 / currentVal) > 0) { System.out.println("Whoops"); } } catch (Exception e) { System.out.println("Caught the error"); } finally { currentVal = 1; } currentMessage = "Inside Static Initializer"; } public static void main(String[] args) { StaticTest st = new StaticTest(); } } |
try-catch and constructors (also uses code above) |
import java.io.IOException; public class InitializerExceptions { // Create a subclass of InitializerExceptions class SubClass extends InitializerExceptions { SubClass() throws Exception { super(); // Note that call to super() is redundant statement } } // Create an instance initializer block that throws an unchecked exception { int i = 0; if (i == 0) throw new IOException("Whoops"); } // Constructor declares IOException in a throws clause // All constructors must declare a throws IOexception clause InitializerExceptions() throws IOException { } public static void main(String[] args) { System.out.println("Executing main()"); System.out.println(StaticTest.currentMessage); try { InitializerExceptions ie = new InitializerExceptions(); } catch (Exception e) { System.out.println("Ignoring the error, " + e.getMessage()); } } } |
Create and invoke a method that throws an exception
Exceptions that a method might or might not throw have to be declared, its basically letting the world know about it. The throws keyword is used to declare an exception
Keywords |
|
throws | used in a method definition to declare the exceptions to be thrown by the method |
throw | used to throw an exception which hopefully will be caught |
Examples |
|
throws/throw | void myFunction() throws myException1, myException2 { ## throws statement Note: the stack above will handle the thrown exception |
Throw checked and unchecked exceptions | public class ThrowsClauseExample { // Custom RuntimeException class ACustomRuntimeException extends RuntimeException { ACustomRuntimeException(String message) { super(message); } } // Custom Exception (not RuntimeException) class ACustomCheckedException extends Exception { ACustomCheckedException(String message) { super(message); } } // Custom Throwable class ACustomThrowable extends Throwable { ACustomThrowable(String message) { super(message); } } // Custom Error class AnError extends Error { AnError(String message) { super(message); } } public static void main(String[] args) { ThrowsClauseExample t = new ThrowsClauseExample(); // For loop allows us to test each exception thrown for (int i = 0; i < 4; i++) { try { switch (i) { case 0: t.methodOne(); break; case 1: t.methodTwo(); break; case 2: t.methodThree(); break; case 3: t.methodFour(); break; } // Catch clause is inside for loop, so execution of // for loop continues after we catch the exception } catch (Throwable e) { System.out.println("In the catch clause of main(): " + e); } } } // Unchecked Runtime Exception Thrown private void methodOne() { throw new ACustomRuntimeException("Error in methodOne"); } // Checked - must satisfy catch or specify - here we catch. private void methodTwo() { try { throw new ACustomCheckedException("Error in methodTwo"); } catch (Exception e) { System.out.println("In the catch clause of methodTwo(): " + e); } } // Checked - must satisfy catch or specify - here we specify // in the throws clause private void methodThree() throws ACustomThrowable { throw new ACustomThrowable("Error in methodThree"); } // Unchecked Error thrown private void methodFour() { throw new AnError("Error in methodFour"); } } |
There are two flavours of exception, the bottomline is if a client can reasonably be expected to recover from an exception make a checked exception, if the client cannot do anything to recover from the exception make it a unchecked exception.
checked | include all subtypes of Exception (excluding classes that extend RuntimeException). Checked exceptions are subject to the handle and declare rule, any method that might throw a checked exception (including methods that invoke methods that can throw a checked exception) must either declare the exception using the throws keyword or handle the exception with an appropriate try/catch. |
unchecked | Errors and Runtime exceptions are referred to as unchecked exceptions, thus you do not need to declare them. |
Checked/Unchecked Example |
|
check/unchecked |
public class exceptionTest { // This class throws the exception back to a calling method // run the throwing back exception method // a checked exception must be caught, you have to have a try and catch block // a unchecked exception which does not have to be caught - notice no try and catch blocks // Here we are throwing back the exception to the calling method note the keyword |
Java incorporates a feature called chained exceptions it allows you to associate another exception with an exception, this is an advanced topic and probably used under some circumstances. The second exception describes the cause of the first exception. To allow chained exceptions two constructors and two methods were added to Throwable
Here is a simple example of a chained exception
Chained exception example | public class ChainedException { static void demoexc() { NullPointerException e = new NullPointerException("top layer"); // this is the original exception - top layer e.initCause(new ArithmeticException("cause")); // this is the underlying exception - the actual cause throw e; } public static void main(String[] args) { try { demoexc(); } catch (NullPointerException e) { System.out.println("Caught: " + e); System.out.println("Original cause: " + e.getCause()); } } } |
When you are coding you sometimes add some debugging code to find out whats going on with your program
Not using assertions | while (true) { |
The above is normal coding when you are trying to find out what values are set to when you program breaks down, once you are done fixing the program you want to remove any debugging code which can be a problem. This is were assertions come in, Assertions let you test your assumptions during development, but the assertion code in-effect evaporates when the program is deployed in production. If the Assertion is not true then a stop-the-world AssertError is thrown (do not ever handle these).
Using Assertions | ## really simple ## Simple Note: if the assert is not true then a AssertionError is thrown never try to handle these |
Assertion have the following rules
There are a number of options that you need to use in order to get assertions working
Compiling | When compiling make sure to add the option (-source <java version>) > javac -source <java version> <class> |
Enabling | When running the application add the option (-ea or enableassertions) > java -ea <class> > java -enableassertions <class> |
Disabling | When running the application add the option (-da or disableassertions) > java -da <class> > java -disableassertions <class> |
Enabling/Disabling | java -ea -da:uk.co.datadisk.graphics Note: we enable all assertions but disable assertions for the graphics class, by default assertions are disabled. |
Here is a list when you should or should not use assertions