Java Exceptions: try, catch and finally

These Java examples use exception handling with the try and catch statements. They handle different Exception classes.
Exceptions. In programs, errors happen. Exceptions help us deal with them. These use an alternative control flow. The program's main control flow terminates and exception handling begins.
Try, catch. Developers use the try and catch keywords to handle exceptions. When an error occurs, a catch block is located and run. The program then continues.
An example. We cause an exception on purpose—we divide by zero. This statement is inside a try statement. The catch-statement is reached. We then display the exception.

Note: In this example, the Exception base class is used. The exception is of type ArithmeticException.

But: The ArithmeticException, derived from Exception, is matched by the Exception catch clause.

Java program that uses try, catch public class Program { public static void main(String[] args) { try { // Divide by zero. int value = 1 / 0; } catch (Exception ex) { // Display exception. System.out.println(ex); } } } Output java.lang.ArithmeticException: / by zero
Catch. A catch clause that matches an Exception will catch any kind of exception. This is the simplest, most basic approach to catching any exception.
NullPointerException. Exceptions often occur when we do not expect them. This program appears correct. It compiles. But when we use length() on a null string, a NullPointerException occurs.length
Java program that causes NullPointerException public class Program { public static void main(String[] args) { // An input string. String name = "sam"; System.out.println(name.length()); // When string is null, an exception occurs. name = null; System.out.println(name.length()); } } Output 3 Exception in thread "main" java.lang.NullPointerException at program.Program.main( Java Result: 1
Unhandled exception. A method that is known to throw an exception must have a "throws" clause in its declaration. An unresolved compilation program (java.lang.Error) otherwise occurs.

Program 1: We see a program that fails compilation. It cannot be executed. A java.lang.Error is reported.

Program 2: This program adds the "throws Exception" clause. It now executes correctly—it throws the Exception during runtime.

Java program that causes compilation error public class Program { public static void main(String[] args) { throw new Exception(); } } Output Exception in thread "main" java.lang.Error: Unresolved compilation problem: Unhandled exception type Exception at program.Program.main( Java program that has no compilation error public class Program { public static void main(String[] args) throws Exception { throw new Exception(); } } Output Exception in thread "main" java.lang.Exception at program.Program.main(
Finally. This block is always run after the try and catch blocks. It does not matter whether an exception is triggered. And sometimes the finally runs, but the catch does not.
Java program that uses finally block public class Program { public static void main(String[] args) { String value = null; try { // This statement causes an exception because value is null. // ... Length() requires a non-null object. System.out.println(value.length()); } catch (Exception ex) { // This runs when the exception is thrown. System.out.println("Exception thrown!"); } finally { // This statement is executed after the catch block. System.out.println("Finally done!"); } } } Output Exception thrown! Finally done!
Finally, no exceptions. This program throws no exception. But it still executes its finally block. The code in finally is always run after the try block is run.

Caution: Unless an exception may occur, this is not a worthwhile construct. In more complex programs, "finally" makes more sense.

Java program that uses finally without exception public class Program { public static void main(String[] args) { try { System.out.println("In try"); } finally { // The finally is run even if no exception occurs. System.out.println("In finally"); } System.out.println("...Done"); } } Output In try In finally ...Done
Exception performance. Exception handling has a cost. In this test, we see whether preventing an exception (with an if-check) is faster than dealing with one in a catch block.

Result: Checking for zero and preventing a division error is faster than handling errors in a try and catch clause.

So: For optimal performance, we should usually code defensively, preventing errors and not dealing with them at all.

Java program that benchmarks exceptions public class Program { public static void main(String[] args) { long t1 = System.currentTimeMillis(); // Version 1: check against zero before division. for (int i = 0; i < 1000000; i++) { int v = 0; for (int x = 0; x < 10; x++) { if (x != 0) { v += 100 / x; } } if (v == 0) { System.out.println(v); } } long t2 = System.currentTimeMillis(); // Version 2: handle exceptions when divisor is zero. for (int i = 0; i < 1000000; i++) { int v = 0; for (int x = 0; x < 10; x++) { try { v += 100 / x; } catch (Exception ex) { // Errors are encountered. } } if (v == 0) { System.out.println(v); } } long t3 = System.currentTimeMillis(); // ... Times. System.out.println(t2 - t1); System.out.println(t3 - t2); } } Output 36 ms: if-check 89 ms: try, catch
ClassCastException. This error occurs when we try to cast a variable (often of type Object) to a class that is not valid. Classes in Java reside in a hierarchy: casts must traverse it.Casts, ClassCastException
NumberFormatException. This occurs when we try to parse a String that does not contain numeric characters. The operation is impossible. This is a common program speed issue.parseInt, NumberFormatException
StackOverflowError. Programs have a limited amount of stack memory. Recursion can sometimes overflow this memory—the program runs out of stack.StackOverflowError

Tip: In my experience, stack overflow is often caused by incorrect recursive calls.

Tip 2: A program, like the one here, can cause a StackOverflowError just by using unchecked recursion.

Java program that encounters StackOverflowError public class Program { static void applyRecursion() { applyRecursion(); } public static void main(String[] args) { // Begin recursion. applyRecursion(); } } Output Exception in thread "main" java.lang.StackOverflowError at program.Program.applyRecursion( at program.Program.applyRecursion( at program.Program.applyRecursion(
Refactoring, null. Whenever an object may be null, we must check it against null before using it. If we omit this check, the program may cease operation. Using a null-check is a simple fix.

But: Other alternatives exist. We can use a special, "null object" instance that handles method calls with no errors.

Tip: The "null object" design pattern is described in the book Refactoring. It eliminates many branches in code.

Programs are complex. When an error occurs, dealing with it within the core control flow adds complexity. Instead we use exception-handling to isolate error conditions.
© 2007-2019 Sam Allen. Every person is special and unique. Send bug reports to
Dot Net Perls