1. Exceptions
>
At long last, programmers thought to standardize and automate error handling. This happened when exceptions were invented. Now the exception mechanism handles 80% of exceptional situations.
If some scholar came up with exceptions, it was likely the subject of his or her doctoral dissertation. If a programmer came up with it, then he may have received a friendly pat on the back from a coworker: "Seems okay, bro."
When an error occurs in a Java program, such as division by 0
, some wonderful things happen:
Step one
A special exception object is created, which contains information about the error that occurred.
Everything in Java is an object, and exceptions are no exceptions 🙂 Exception objects have their own classes, and the only thing that distinguishes them from ordinary classes is that they inherit the Throwable
class.
Step two
The exception object is "thrown". Perhaps the wording here could be better. "Throwing an exception" is more like triggering a fire alarm or sounding a "DEFCON 1" alert.
When an exception is thrown to the Java machine, the normal operation of the program stops and "emergency protocols" begin.
Step three
The method in which the exception was thrown exits immediately. The exception is passed to the calling method, which also exits immediately. And so on down the chain until the main
method exits. When the main
method terminates, so does the program.
Example:
Code | Console output |
---|---|
|
|
An exception occurs on line 20: division by 0. The Java machine immediately creates an exception — an ArithmeticException
object and "throws" it to the method.
The divide()
method ends immediately, so we never see the string: Nothing terrible happened: 0. The program returns to the endTheWorld()
method, and the situation repeats itself: there is an unhandled exception in the system, which means that the endTheWorld()
method also terminates abnormally. Then the main
method terminates, and the program stops.
What is the purpose of these exceptions? Well, you can write your own code to catch particular types of exceptions and write your own logic to handle exceptional situations.
2. Catching exceptions: try-catch
Java has an exception catching mechanism that lets you halt this abnormal termination of methods. It looks like this:
try
{
// Code where an exception might occur
}
catch(ExceptionType name)
{
// Exception handling code
}
This construct is called a try-catch
block.
Code where exceptions may occur is wrapped in curly braces, preceded by the word try
.
After the curly braces, we have the catch
keyword and, inside parentheses, the declaration of an exception variable. This is followed by curly braces that wrap the code to be executed if an exception of the specified type occurs.
If no exceptions are thrown during execution of the "primary code", then the code inside the catch block will not be executed. If an exception occurs, then it will be (if the type of the thrown exception is the same as the type of the variable in the parentheses).
Example:
Code | Console output |
---|---|
|
|
3. Multiple catch
blocks
In theory, all sorts of exceptions can be thrown in a block of code. Some you will want to handle one way, others another way, and still others you will decide not to handle at all.
Java developers decided to help you out and let you write not one but many catch
blocks after the try
block.
try
{
// Code where an exception might occur
}
catch (ExceptionType1 name1)
{
// Code for handling ExceptionType1
}
catch (ExceptionType2 name2)
{
// Code for handling ExceptionType2
}
catch (ExceptionType3 name3)
{
// Code for handling ExceptionType3
}
Example:
Code | Console output |
---|---|
|
|
4. Order of catch
blocks
Exceptions that occur in a try
block can only be caught by a single catch
block. You cannot have an exception handling situation where the code from multiple catch
blocks gets executed.
But the order of the blocks matters.
You can have a situation where an exception could be caught by multiple blocks. If that is the case, then the exception will be caught by whichever catch block comes first (closest to the try
block).
How can you have a situation where multiple catch blocks can catch the same exception?
All exceptions belong to a single inheritance hierarchy — see the diagram.
An ArithmeticException
object can be assigned to a variable whose type is ArithmeticException
or any of its ancestor classes: RuntimeException
, Exception
and Throwable
— see the diagram.
We'll talk more about inheritance and ancestor classes in Level 21.
This code will compile just fine:
Benefits of inheritance: |
---|
|
So you can catch an ArithmeticException
with any of the 4 catch
blocks above.
Example 1:
Code | Console output |
---|---|
|
|
In this example, the ArithmeticException
can be caught by both the catch (Exception e)
and catch (ArithmeticException e)
blocks. It will be caught by the block closest to the try
block — the first catch
block.
To avoid surprises, it is best to place catch
blocks that can catch nearly every exception near the end of the list of catch
blocks.
The Throwable
type is generally capable of catching every possible exception in Java. If you put it in the first catch
block, then the code won't compile, since the compiler knows that there are unreachable blocks of code.
GO TO FULL VERSION