Java 11 Developer Certification - Exception Handling
April 19, 2021
What we are covering in this lesson
- What is an Exception
- Exception Handling Overview
- Error Class
- Exception Class
- Flow of Exception
- Code Example
What is an Exception
The thing to remember in programming is the BAD STUFF HAPPENS! We can plan for the bad stuff and be proactive on what to do when the bad stuff happens, OR we can be reactive to the unexpected and unplanned. Usually, we try to do both!
Java provides a framework for dealing with errors in your application, giving you as much control and customization as you desire.
You can use out-of-the-box exception classes as defined by the java.lang package and other sdk libraries, OR you can extend and customise one of Java’s exception classes and the information attached to it.
You can prevent an exception from interrupting the flow of your application by handling it immediately, or just ignoring it, or you can interrupt the flow of the current method, it’s calling method and so on, up to stack trace, depending on your own identification of the severity of the problem.
Java actually supports several varieties of exceptions. The Error - considered the most severe and usually a system error from which there’s no recovery. The Exception - which is less severe.
In addition, Java categorises exceptions as either Checked exception or not. Checked exceptions must be dealt with using something called the Catch or Specify Requirement, or you’ll get a compiler error. Unchecked exceptions which can be either Error or Exception parent class, are not checked by the compiler for the same requirements.
The advantages of exceptions are
- Error-handling Code can be separated from Regular Code
- Errors can be propagated up the call stack
- Error Types can be grouped and differentiated like any other objects.
Exception Handling Overview
An exception is an event that occurs during the execution of a program, that disrupts the normal flow of instructions.
It’s usually caused by an abnormal condition or an unexpected use of a resource.
The java.lang.Throwable class and all its subclasses are, collectively, the exception classes.
This Throwable class has two sub classes - Exception and Error. You can check it in full detail here
Error class
The Error Class as per Java’s naming standard is to use the Error suffix for classes that extend Error.
When a dynamic linking failure or other hard failure in the Java virtual machine occurs, the virtual machine throws an Error.
The IOError is probably the best know Error in this hierarchy, but some others are -
- AnnotationFormatError
- AssertionError
- CoderMalfunctionError
- FactoryConfigurationError
-
LinkageError, which includes the
- BootstrapMethodError
- ClassCircularityError
- ClassFormatError
- ExceptionInitializerError
- IncompatibleClassChangeError
- NoClassDeffFoundError
- UnsatsifiedLinkError
- VerifyError
- ServiceConfigurationError
- ThreadDeath
- TransformerFactoryConfigurationError
-
VirtualMachineError which includes the
- InternalError
- OutOfMemoryError
- StackOverflowError
- UnknownError
Exception class
The Exception Class as per Java’s naming standard is to use the Exception suffix for classes that extend Exception.
Objects that derive from the Exception class are generally the predictable or known errors that indicate that a problem occurred, but it’s not necessarily a serious problem, and your recovery options may exist.
We would be discussion this class in full detail.
Flow of Exception
Now that we know what errors and exceptions are, we must know what happens When an error happens.
When an error happens, the method from which the error originated creates a special object, an exception object, and hands it off to the runtime system.
The exception object contains information about the error, and the state of the programme when the error occurred.
Creating an exception object and handing it to the runtime system is called throwing an exception. You can manually throw an exception by identifying a scenario you consider an error, but in many cases, it’s the Java Virtual Machine throwing exceptions automatically.
Once an exception is thrown, the runtime system then attempts to find something to handle the exception.
Handling the exception means there’s code that identifies itself as responsible for responding to the error condition that occurred.
The runtime system trying to find a handler for an exception object could be likened to a frustrated sales customer working his or her way up through management as they query whether this particular manager can handle their complaint. The manager will refer the customer to the next manager above themselves or hopefully at some point handle the complaint themselves and let the customer progress to the next step of the sale or refund.
A method can identify itself as a responsible party, able to handle the exception, by declaring a block of code called an exception handler.
The runtime system searches the call stack for a method that contains such a block of code, starting with the current method, and searching the call stack in reverse order until it finds a method with a handler.
Remember that a call stack is a listing of programme counter (PCs) addresses representing instructions, or method calls, from within the programme which identifies the path the application executed to get to the current instruction or statement.
The runtime system looks for a handler that must catch the right type of exception that was thrown, or the runtime system will continue to look for a matching responsible party. And if no handler is ever found, the thread that creates the error or exception dies.
You can check here, the diagram explains the details of exception flow.
Code Examples
The below code shows the basic try catch logic when exceptions are thrown.
We are trying to open a non-existent file in the try block, which will throw a FileNotFoundException. Based on the exception instance, we are printing the message and further printing the hierarchy of exception thrown from the method printErrorStructure.
package maxCode.online.exceptions;
import java.io.FileInputStream;
import java.io.IOError;
import java.io.IOException;
public class ThrowableExamples {
public static void main(String[] args) {
ThrowableExamples te = new ThrowableExamples();
String filename = "This_File_Does_Not_Exist.out";
//te.throwAnError();
// Try to open file with filename defined above
try {
//te.throwAnError();
FileInputStream f = new FileInputStream(filename);
} // This statement catches anything thrown at you.
catch (Throwable error) {
// Check to see if it's an IOException and print something
if (error instanceof IOException) {
System.out.println("Something went wrong with the" + " processing of " + filename);
}
printErrorStructure(error);
}
}
// 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);
}
// Mocking an IOError ...
private void throwAnError() throws IOError {
throw new IOError(new Throwable("Testing"));
}
}
Output
Something went wrong with the processing of This_File_Does_Not_Exist.out
Error caught was:
java.io.FileNotFoundException
-- java.io.IOException
---- java.lang.Exception
------ java.lang.Throwable
The output shows that we actually caught a FileNotFoundException which is a subclass of IOException.
We have later added a method throwAnError, and the calls to this method are commented out in the above code. In case we uncomment one of those - the one within the try block - we will get the below error.
Error caught was:
java.io.IOError
-- java.lang.Error
---- java.lang.Throwable
So this was a very generic example that didn’t discriminate between error or exception or between the two significant categories of exception, “Checked” and “UnChecked.”
The following table explains what type of errors are checked and unchecked.
Class Type | Checked or Unchecked | Must satisfy the catch or Specify Requirement |
---|---|---|
Throwable or any custom exception which extends Throwable | Checked Exception | YES |
Error or any custom exception which extends Error | Unchecked Exception | NO |
Exception - Any Exception subclassed directly or indirectly from RuntimeException - these are called Runtime Exceptions | Unchecked Exception | NO |
Exception - Any Exception not subclassed from RuntimeException or its subclasses | Checked Exception | YES |
A checked exception is a special designation, for a group of exceptions that the compiler forces compliance of ‘The Catch or Specify’ requirement. An unchecked exception will not be checked by the compiler.
Now let’s look at some runtime exceptions.
Exception | Details |
---|---|
ArithmeticException | For e.g., an integer divide by zero throws an instance of this class |
ArrayIndexOutOfBoundsException | Thrown to indicate that an array has been accessed with illegal index |
ArrayStoreException | Attempt made to store the wrong type of object into an array of objects |
ClassCastException | Attempt to cast an object into a subclass of which it is not an instance |
IndexOutOfBoundsException | Thrown to indicate that an index of some sort is out of range |
NegativeArraySizeException | Thrown if an application tries to create an array with negative size |
NullPointerException | Thrown when an application attempts to use null in a case where an object is required |
SecurityException | Thrown by the security manager to indicate a security violation |
Since these are runtime exceptions, the compiler doesn’t force you to write code to check for the exception. In other words, the try/catch block or specify the exception in the throws section of the wrapping method declaration.
Only a check exception requires compliance, to ‘The Catch or Specify’ requirement. A checked exception is neither an Error, nor a runtime exception. OR in simpler terms, Errors and runtime exceptions are unchecked exceptions, everything else is a checked exception.
The Catch or Specify Requirement states that code that might throw certain exceptions, must be enclosed by either of the following:
- A try statement that catches the exception. The try must provide an appropriate handler for the exception.
- A method that specifies that it can throw the exception. The method must provide a throws clause that lists the exception or an appropriate exception type.
In terms of code, if a client can be expected to recover from the exception, you inform the client by making it a checked exception, and identifying the exception in the throws clause of the method.
If a client cannot be expected to recover from the exception, you don’t need to make it a checked exception.
Now if we look back at the code, and uncomment the lines te.throwAnError (above the try block), the compiler doesnt throw an error - which confirms that IOError subclassed from Error is not a checked exception.
If we run the code, we get below error message
Exception in thread "main" java.io.IOError: java.lang.Throwable: Testing
at maxCode.online.exceptions.ThrowableExamples.throwAnError(ThrowableExamples.java:47)
at maxCode.online.exceptions.ThrowableExamples.main(ThrowableExamples.java:12)
Caused by: java.lang.Throwable: Testing
... 2 more
This was a very basic example showing the exception - checked and unchecked - and Errors. In next sections we will look at these in detail.