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 throw CheckedExceptionA, then only catch CheckedExceptionA or catch 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:

500 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.

Exception _0.excalidraw

This happens for both runtime exceptions and checked exceptions.

In short:

Checked ExceptionRuntime Exception
Compiler checks for try or throwsNo compiler check
JVM goes through call stackJVM goes through call stack

Resources