o7planning

Java Exception Handling Tutorial with Examples

  1. What is Exception?
  2. Exception Hierarchy
  3. Handling exception with try-catch
  4. try-catch-finally
  5. Exception Wrapping
  6. RuntimeException and subclasses

1. What is Exception?

First, let's see the following illustration example:
In this example, there is an part of error code which results from the division by 0. The division by 0 causes the exception: ArithmeticException
HelloException.java
package org.o7planning.tutorial.exception;

public class HelloException {

	public static void main(String[] args) {

		System.out.println("Three");

		// This division has no problem.
		int value = 10 / 2;

		System.out.println("Two");

		// This division has no problem.
		value = 10 / 1;

		System.out.println("One");

		// This division has problem, divided by 0.
		// An error has occurred here.
		value = 10 / 0;

		// And the following code will not be executed.
		System.out.println("Let's go!");

	}

}
The result from running the example:
You can see the notification on the Console screen. The error notification is very clear, including the information of code line.
Three
Two
One
Exception in thread "main" java.lang.ArithmeticException: / by zero
    at org.o7planning.tutorial.exception.HelloException.main(HelloException.java:31)
Let see the flow of the program through the following illustration:
  • The program runs normally from step (1), (2) to (5).
  • In step (6), the program divided by 0.
  • The program jumps out of main method, and the (7) code line has not been executed.
We will modify code of above example.
HelloCatchException.java
package org.o7planning.tutorial.exception;

public class HelloCatchException {

	public static void main(String[] args) {

		System.out.println("Three");

		// This division has no problem.
		int value = 10 / 2;

		System.out.println("Two");

		// This division has no problem.
		value = 10 / 1;

		System.out.println("One");

		try {
			// This division has problem, divided by 0.
			// An error has occurred here.
			value = 10 / 0;

			// And the following code will not be executed.
			System.out.println("Value =" + value);

		} catch (ArithmeticException e) {
			// The code in the catch block will be executed.
			System.out.println("Error: " + e.getMessage());

			// The code in the catch block will be executed.
			System.out.println("Ignore...");

		}

		// This code will be executed.
		System.out.println("Let's go!");

	}

}
And the results of running the example:
Three
Two
One
Error: / by zero
Ignore...
Let's go!
We will explain the flow of the program by the following illustration images.
  • Steps (1) to (5) are completely normal.
  • Exception occurs in step (6), the problem divided by zero.
  • Immediately it jumps in executing the command in catch block, step (7) is skipped.
  • Step (8), (9) is executed.
  • Step (10) is executed.

2. Exception Hierarchy

This is the model of hierarchical map of Exception in Java.
  • The highest class is Throwable
  • Two direct subclasses is Error and Exception.
In Exception branch there is a RuntimeException subclass including exceptions unchecked by Java in the compile-time. The meaning of check and uncheck in the compile-time is illustrated in examples of the next part.
Note: Your class should inherited from two branches Error or Exception, not directly inherited from Throwable.
Error
When a dynamic linking failure or some other "hard" failure in the virtual machine occurs, the virtual machine throws an Error. Typical Java programs should not catch Errors. In addition, it's unlikely that typical Java programs will ever throw Errors either.
Example of dynamic linking: For example, when you call a library that library is missing a class, or missing a method, in which case the error will be thrown.
Exceptions
Most programs throw and catch objects that derive from the Exception class. Exceptions indicate that a problem occurred but that the problem is not a serious systemic problem. Most programs you write will throw and catch Exceptions.

The Exception class has many descendants defined in the Java packages. These descendants indicate various types of exceptions that can occur. For example, NegativeArraySizeException indicates that a program attempted to create an array with a negative size.

One Exception subclass has special meaning in the Java language: RuntimeException.
Runtime Exceptions
The RuntimeException class represents exceptions that occur within the Java virtual machine (during runtime). An example of a runtime exception is NullPointerException, which occurs when a method tries to access a member of an object through a null reference. A NullPointerException can occur anywhere a program tries to dereference a reference to an object. The cost of checking for the exception often outweighs the benefit of catching it.
Because runtime exceptions are so ubiquitous and attempting to catch or specify all of them all the time would be a fruitless exercise (and a fruitful source of unreadable and unmaintainable code), the compiler allows runtime exceptions to go uncaught and unspecified.
The Java packages define several RuntimeException classes. You can catch these exceptions just like other exceptions. However, a method is not required to specify that it throws RuntimeExceptions. In addition, you can create your own RuntimeException subclasses. Runtime Exceptions--The Controversy contains a thorough discussion of when and how to use runtime exceptions.

3. Handling exception with try-catch

We write a class that inherits from Exception.
AgeException.java
package org.o7planning.tutorial.exception.basic;

public class AgeException extends Exception {

  public AgeException(String message) {
      super(message);
  }

}
TooYoungException.java
package org.o7planning.tutorial.exception.basic;

public class TooYoungException extends AgeException {

 public TooYoungException(String message) {
     super(message);
 }

}
TooOldException.java
package org.o7planning.tutorial.exception.basic;

public class TooOldException extends AgeException {

 public TooOldException(String message) {
     super(message);
 }

}
And AgeUtils class with static methods for the examination of age.
AgeUtils.java
package org.o7planning.tutorial.exception.basic;

public class AgeUtils {

	// This method checks the age.
	// If age is less than 18, it will throw TooYoungException
	// If age greater than 40, it will throw TooOldException
	public static void checkAge(int age) throws TooYoungException, TooOldException {
		if (age < 18) {
			// If age is less than 18, an exception will be thrown.
			// This method ends here.
			throw new TooYoungException("Age " + age + " too young");
		} else if (age > 40) {
			// If age greater than 40, an exception will be thrown.
			// This method ends here.
			throw new TooOldException("Age " + age + " too old");
		}
		// If age is between 18-40.
		// This code will be executed.
		System.out.println("Age " + age + " OK!");
	}
}
Checked Exception & Unchecked Exception:
  • AgeException are subclasses of Exception, TooOldException and TooYoungException 2 direct subclasses of AgeException,so they are "Checked Exception"
  • Trong method AgeUtils.checkAge(int) có ném ra ngoài các ngoại lệ này vì vậy trên khai báo của method bạn cần phải liệt kê chúng thông qua từ khóa "throws". Hoặc bạn có thể khai báo ném ra ở mức tổng quát hơn
    • throws Exception.
  • Tại các nơi sử dụng AgeUtils.checkAge(int) cũng phải có sử lý để bắt các ngoại lệ đó, hoặc tiếp tục ném ra vòng ngoài.
"Checked exception" will be checked by "Java Compiler".
You have two choices:
TryCatchDemo1.java
package org.o7planning.tutorial.exception.basic;

public class TryCatchDemo1 {

	public static void main(String[] args) {

		// Start Recruiting...
		System.out.println("Start Recruiting ...");
		// Check age.
		System.out.println("Check your Age");
		int age = 50;

		try {

			AgeUtils.checkAge(age);

			System.out.println("You pass!");

		} catch (TooYoungException e) {

			// Do something here ..
			System.out.println("You are too young, not pass!");
			System.out.println(e.getMessage());

		} catch (TooOldException e) {
			// Do something here ..
			System.out.println("You are too old, not pass!");
			System.out.println(e.getMessage());

		}

	}
}
In the following example, we will catch exceptions through parent exceptions (super exception class).
TryCatchDemo2.java
package org.o7planning.tutorial.exception.basic;

public class TryCatchDemo2 {

	public static void main(String[] args) {

		// Start Recruiting
		System.out.println("Start Recruiting ...");
		// Check your age.
		System.out.println("Check your Age");
		int age = 15;

		try {
			// This may raise TooOldException or TooYoungException exception
			AgeUtils.checkAge(age);

			System.out.println("You pass!");

		} catch (AgeException e) {
			// If an exception occurs, type of AgeException.
			// This catch block will be executed.
			System.out.println("Your age invalid, you not pass");
			System.out.println(e.getMessage());

		}
	}
}
You can also group different exceptions to the same block to handle if they have similar handling ways on your logic program.
TryCatchDemo3.java
package org.o7planning.tutorial.exception.basic;

public class TryCatchDemo3 {

	public static void main(String[] args) {

		System.out.println("Start Recruiting ...");

		System.out.println("Check your Age");
		int age = 15;

		try {
			// This may raise TooOldException or TooYoungException exception
			AgeUtils.checkAge(age);

			System.out.println("You pass!");

		} catch (TooYoungException | TooOldException e) {
			// Catch multi exceptions in one block.
			System.out.println("Your age invalid, you not pass");
			System.out.println(e.getMessage());

		}
	}

}

4. try-catch-finally

We have got accustomed with catching error through try-catch block. Try-catch-finally is used to fully handle exception.
try {

   // Do something here.
} catch (Exception1 e) {

   // Do something here.
} catch (Exception2 e) {

   // Do something here.
} finally {

   // The finally block is always executed.
   // Do something here.
}
TryCatchFinallyDemo.java
package org.o7planning.tutorial.exception.basic;

public class TryCatchFinallyDemo {

	public static void main(String[] args) {

		String text = "001234A2";

		int value = toInteger(text);

		System.out.println("Value= " + value);

	}

	public static int toInteger(String text) {
		try {

			System.out.println("Begin parse text: " + text);

			// This may raise the NumberFormatException.
			int value = Integer.parseInt(text);

			return value;

		} catch (NumberFormatException e) {

			// In the case of 'text' is not a number.
			// This catch block will be executed.
			System.out.println("Number format exception " + e.getMessage());

			// Returns 0 if NumberFormatException occurs
			return 0;

		} finally {

			System.out.println("End parse text: " + text);

		}
	}

}
This is the flow of the program. Finally block is always executed.

5. Exception Wrapping

We need a some class participated in this example:
  • Person: Simulate a participant recruitment into the company with the information: Name, age, gender.
  • GenderException: Gender Exception.
  • ValidateException: Exception evaluate a candidate.
  • ValidateUtils: Class with static method evaluate candidates.
    • Valid if age between 18-40 and male
Person.java
package org.o7planning.tutorial.exception.wrap;

public class Person {

  public static final String MALE = "male";
  public static final String FEMALE = "female";

  private String name;
  private String gender;
  private int age;

  public Person(String name, String gender, int age) {
      this.name = name;
      this.gender = gender;
      this.age = age;
  }

  public String getName() {
      return name;
  }

  public void setName(String name) {
      this.name = name;
  }

  public String getGender() {
      return gender;
  }

  public void setGender(String gender) {
      this.gender = gender;
  }

  public int getAge() {
      return age;
  }

  public void setAge(int age) {
      this.age = age;
  }
}
GenderException.java
package org.o7planning.tutorial.exception.wrap;

// Gender Exception.
public class GenderException extends Exception {
 
      public GenderException(String message)  {
    	  super(message);
      }
}
Class ValidateException wrap other Exception.
ValidateException.java
package org.o7planning.tutorial.exception.wrap;

public class ValidateException extends Exception {
	
	// Wrap an Exception
	public ValidateException(Exception e)  {
		super(e);
	}

}
ValidateUtils.java
package org.o7planning.tutorial.exception.wrap;

import org.o7planning.tutorial.exception.basic.AgeUtils;

public class ValidateUtils {

	// Method to check a person, 
	public static void checkPerson(Person person) throws ValidateException {
		try {

			// Check age.
			// Valid if between 18-40
			// This method can throw TooOldException, TooYoungException.		
			AgeUtils.checkAge(person.getAge());

		} catch (Exception e) {

			// If not valid
			// Wrap this exception by ValidateException, and throw
			throw new ValidateException(e);

		}

		// If this person is Female, ==> invalid.
		if (person.getGender().equals(Person.FEMALE)) {

			GenderException e = new GenderException("Do not accept women");
			throw new ValidateException(e);

		}
	}

}
WrapperExceptionDemo.java
package org.o7planning.tutorial.exception.wrap;

public class WrapperExceptionDemo {

	public static void main(String[] args) {

		// A Candidate.
		Person person = new Person("Marry", Person.FEMALE, 20);

		try {

			// Exceptions may occur here.
			ValidateUtils.checkPerson(person);

		} catch (ValidateException wrap) {

			// Get the real cause.
			// May be TooYoungException, TooOldException, GenderException.
			Exception cause = (Exception) wrap.getCause();

			if (cause != null) {
				System.out.println("Not pass, cause: " + cause.getMessage());
			} else {
				System.out.println(wrap.getMessage());
			}

		}
	}

}

6. RuntimeException and subclasses

RuntimeException class and its subclasses are all "Unchecked exceptions". It is not checked by Java compiler in the compile-time. In some cases, you can write your own exceptions inherited from this branch.

Below is some classes belonging to RuntimeException branch (Of course, that's not all).
Some examples handling this type of exceptions:
NullPointerException
This is one of the most common exceptions that usually causes error to the program. Exception is thrown out when you call method or access to fields of an null object.
NullPointerExceptionDemo.java
package org.o7planning.tutorial.exception.runtime;

public class NullPointerExceptionDemo {

	// Example, here is a method that can return null string.
	public static String getString() {
		if (1 == 2) {
			return "1==2 !!";
		}
		return null;
	}

	public static void main(String[] args) {

		// This is a variable that references is not null.
		String text1 = "Hello exception";

		// Call the method to get the string length.
		int length = text1.length();

		System.out.println("Length text1 = " + length);

		// This is a variable that references is null.
		String text2 = getString();

		// Call the method to get length of string.
		// NullPointerException will occur here.
		// It is an exception occurs at runtime (type of RuntimeException).
		// Java compiler does not force you to catch it at compile-time.
		length = text2.length(); // ==> exception!

		System.out.println("Finish!");
	}

}
Results of running the example:
Length text1 = 15
Exception in thread "main" java.lang.NullPointerException
    at org.o7planning.tutorial.exception.runtime.NullPointerExceptionDemo.main(NullPointerExceptionDemo.java:51)
In reality, like handling other exceptions, you can use try-catch to catch and handle this exception. However, that is mechanical, normally, we should check to ensure that the object not null value before using it.

You can correct the above code to make it similar to the following one with the avoidance of NullPointerException:
// getString() method return a null value.
// This is a variable has reference is null.
String text2 = getString();

// Check to make sure 'text2' is not null.
// Instead of using try-catch.
if (text2 != null) {
  length = text2.length();
}
ArrayIndexOfBoundException
This exception occurs when you try to access to the element whose index are invalid on array. For example, an array has 10 elements, but you access to the element with index 20.
ArrayIndexOfBoundsExceptionDemo.java
package org.o7planning.tutorial.exception.runtime;

public class ArrayIndexOfBoundsExceptionDemo {

	public static void main(String[] args) {

		String[] strs = new String[] { "One", "Two", "Three" };
		// Access to the element at index 0.
		String str1 = strs[0];

		System.out.println("String at 0 = " + str1);

		// Access to the element at index 5.
		// ArrayIndexOfBoundsException occur here.
		String str2 = strs[5];

		System.out.println("String at 5 = " + str2);

	}

}
To avoid ArrayIndexOfBoundsException you should check the array instead of using try-catch.
if (strs.length > 5) {
   String str2 = strs[5];
   System.out.println("String at 5 = " + str2);
} else {
   System.out.println("No elements with index 5");
}

Java Basic

Show More