Java uses the Exception
class to handle exceptions. More specifically, when a line of code has an error, the method associated with it creates an Exception
object which is passed around by the runtime engine.
Java also defines a subclass of Exception - RuntimeException
that specifically relate to exception objects that are created during runtime, also called runtime exceptions and are handled by the JVM.
Furthermore, Java introduces a new type of exception - Checked exceptions. Compile-time or checked exceptions are exceptions that are handled by the compiler first, and then by the JVM. An example of a checked exceptions is java.io.FileNotFoundException
.
try
, catch
and finally
Java provides three keywords reserved for handling exceptions: try, catch, finally
try
{
//Potentially dangeorus code.
}
catch ExceptionA
{
//Code that handles what to do when ExceptionA is created.
}
catch ExceptionB
{
//Same shtick, but with ExceptionB. Note that if
//ExceptionA and ExceptionB are raised, both blocks excute in order
}
finally
{
//This code *always* runs after the try. Even if an exception occurs!
}
try
Is used to ‘attempt’ to run any potentially ‘dangerous’ or erroneous code. It lets the Java compiler know that a catch
is going to follow, to manage the potential Exception
that might be generated.
You can also use a try-with
which is simply enclosing a statement as such:
try (with Something) {
//Other stuff
}
So why use it?
When you do try-with
, it automatically closes any resources declared inside the try statement. Essentially, it’s the same as using a finally
block which loses the resource, but it also prevents a concept known as exception masking
catch
This is where the exception handling really occurs. Depending on how bad the exception is, the program could re-attempt or try to recover, such as by re-prompting for input in the case of invalid input, or try another generation for a random-generated process. In severe exceptions, it would output an error message to help in debugging and then exit.
When catching exceptions, it’s good practice to put more specific exceptions first, due to how the compiler searches the stack trace:
finally
This is an optional keyword that signifies code that should be run after the try
block even if no exception occurs. This is usually used for closing files - java.io.FileReader.close()
or returning back resources.
A unique thing about finally
is that it doesn’t care about control keywords like return
, continue
or break
. It will run regardless!
Compiler Exception Checks
In Java, all checked exceptions need to fulfil the Catch or Specify requirement, which states that every method that may throw a checked exception must have either:
- A
try-catch
block to handle and catch that specific exception. This means if the code could potentially throwCheckedExceptionA
, then onlycatch CheckedExceptionA
orcatch SuperCheckedException
is valid (A’s super classes). - or a
throws
keyword onto a method, stating it can throw the method. This is useful for exception chaining.
If not the compiler raises an error:
error: unreported exception [Exception]; must be caught or declared to be thrown
JVM Checking Call Stack
When a program is compiled, a function call stack is created. For each function call, a new block is added onto the stack:
When an exception occurs, the runtime engine checks for handles in a reverse manner, until it finds a suitable handler. If not, the program crashes.
This happens for both runtime exceptions and checked exceptions.
In short:
Checked Exception | Runtime Exception |
---|---|
Compiler checks for try or throws | No compiler check |
JVM goes through call stack | JVM goes through call stack |