Java Exceptions: try, catch and finally

Use exception handling with the try and catch statements. 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. A catch clause that matches an Exception will catch any kind of exception. This is the simplest way to catch any exception.
Step 1: We cause an exception on purpose—we divide by zero. This statement is inside a try block.
Step 2: The ArithmeticException, derived from Exception, is matched by the Exception catch clause. We then display the exception.
Note: In this example, the Exception base class is used. The exception is of type ArithmeticException.
Java program that uses try, catch public class Program { public static void main(String[] args) { try { // Step 1: divide by zero. int value = 1 / 0; } catch (Exception ex) { // Step 2: display exception. System.out.println(ex); } } } Output java.lang.ArithmeticException: / by zero

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(Program.java:9) 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(Program.java:5) 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(Program.java:5)

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

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(Program.java:6) at program.Program.applyRecursion(Program.java:6) at program.Program.applyRecursion(Program.java:6)...

Benchmark, exception. Exception handling has a cost. For optimal performance, we should usually code defensively, preventing errors and not dealing with them at all.
Version 1: In this version of the code, we use an if-statement to prevent any exceptions from occurring.
Version 2: Here we just divide, and handle exceptions in a catch block if we cause an error.
Result: Checking for zero and preventing a division error is faster than handling errors in a try and catch clause.
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

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-2020 Sam Allen. Every person is special and unique. Send bug reports to info@dotnetperls.com.