ZOFTINO.COM android and web dev tutorials

Java Exceptions

In any program, there can be lines of code which may not be executed in certain situations. If run time environment faces this situation it will terminate the program. It is developer’s responsibility to either prevent this situation or provide alternate execution paths in these situations. This tutorial explains what Java language offer to handle these situations and how you can use it to prevent application crashes and provide best user experience for users of your application.

Table of Contents

Java Exception

In a method, a line of code may not be executable by runtime due to unknown or unexpected situation, the situation for that piece of code can occur sometimes or always, this situation is called exception. Runtime environment captures the situation as object containing where it happened, type of it, etc., and propagates it thru stack of the method calls. This propagation of exception object is called throwing an exception and it is propagated so that other parts of the program can do something with the exception object.

Now let’s understand java exception by creating a program that crashes or gets terminated without executing all statements.

public class MainClass {
	public static void main(String[] args) {
		javaExceptionTest();
	}
	public static void javaExceptionTest() {
		String s = null;
		if(s.equals("test")) {
			System.out.println("inside test condition");
		}
		System.out.println("after the test condition");
	}
}

The above program will fail to run completely and not execute print statement. It fails at the if condition because the string variable s doesn’t have any value assigned to it and equals method is invoked on it. Below is the error.

Exception in thread "main" java.lang.NullPointerException
	at com.zoftino.java.funda.wrap.MainClass.javaExceptionTest(MainClass.java:15)
	at com.zoftino.java.funda.wrap.MainClass.main(MainClass.java:11)

In this example, at failure point, NullPointerException object is created with information about exception and complete method call stack details. The exception is propagated thru the call stack till it finds a handler. If no handler is found, program gets terminated. Next section explains about exception handlers.

Catching and Handling Exceptions

Using try and catch block, you can handle exceptions and provide alternate path of execution. You need to add the code which can cause exception to try block. Then you need to attach handler to it by adding catch block. Within the catch block, you can add code that needs to be run in the exception scenario.

Let’s use the same example and add try block around the code that causes failure. In the handler meaning in the catch block, we will add a print statement. The catch block code will run if NullPointerException occurs.

	public static void javaExceptionTest() {
		try {
			String s = null;
			if(s.equals("test")) {
				System.out.println("inside test condition");
			}
			
		} catch (NullPointerException e) {
			System.out.println("exception occured test failed");
		}
		System.out.println("after the test condition");
	}

Here is the output.

exception occured test failed
after the test condition

Now because of the try and catch blocks, the program ran completely without crashing. Note that exception occurred, but it is handled and handler code in the catch block got executed.

Catch Block

We have seen how exceptions are handled using the catch block by attaching it to try block. You can add multiple catch blocks to a try block to handle different exceptions and provide different handling behavior for each exception.

For example, if you run below program with one item in the list, you will get IndexOutOfBoundsException and if you run it with more than one item in the list, you will get NumberFormatException. Two exceptions can be handled using two catch blocks as shown below.

public class MainClass {
	public static void main(String[] args) {
		List<String> items = new ArrayList<>();
		items.add("test");
		items.add("testtwo");
		
		try {
			String itemTwo =  items.get(1);
			int value = Integer.valueOf(itemTwo);
		}catch(IndexOutOfBoundsException ibe) {
			System.out.println("IndexOutOfBoundsException");
		}catch(NumberFormatException cce) {
			System.out.println("NumberFormatException");
		}
	}

Multiple exceptions can be handled using single catch block and Exception class.

try {
	String itemTwo =  items.get(1);
	int value = Integer.valueOf(itemTwo);
}catch(Exception e) {
	System.out.println("exception "+e);
}

From Java SE 7, multiple exceptions can be handled in one catch block by specifying exceptions separated by | as shown below.

try {
	String itemTwo =  items.get(1);
	int value = Integer.valueOf(itemTwo);
}catch(IndexOutOfBoundsException|NumberFormatException e) {
	System.out.println("exception "+e);
}

Finally Block

Finally block can be attached to a try block and the code in the finally block is run always in the exception as well as non exception scenarios. This block is used to keep such code that needs to be always executed as any clean up code for releasing resource like closing files.

The only situation in which the finally block may not execute is when JVM exits or when the thread in which it is running is interrupted.

In the below example, though return statements exist before the finally block, the block gets executed every time.

public static String readFileToString(String fileName){
	StringBuilder contentBuilder = new StringBuilder();
	Scanner sc = null;
	File f = new File(fileName);
	
	try {
		sc = new Scanner(f,"UTF-8");

		while(sc.hasNextLine()){			
			String line = sc.nextLine();
			contentBuilder.append(line);
		}
		return contentBuilder.toString();
	} catch (FileNotFoundException e) {
		System.out.println("file not found");
		return "";
	}finally {
		if(sc != null) {
			sc.close();
		}
		System.out.println("final block clean up");
	}
}

Try with Resource

Try with resource statement is used to automatically close the resource created within it. Any resource, which implements AutoCloseable interface and created in try statement, is automatically closed in normal flow as well as exception flow.

In the below example, FileWriter and BufferedWriter are resources created in the try statement. It is not required to close these objects manually. The example also shows that you can attach catch block to try-with-resource statement.

	public void writeToFileNonXml(List<String> strings, String outFileNme){
		File file = new File(outFileNme);

		try(FileWriter fw = new FileWriter(file.getAbsoluteFile())){
			
			try(BufferedWriter bw = new BufferedWriter(fw)){
				for(String item:  strings) {
					bw.write(item);
					bw.newLine();
				}		
			}
			
		} catch (IOException e) {
			System.out.println("IO EXCEPTION");
		}

	}

In the above example, we used two try-with-resource statements. Instead of two separate try with resource statements, we can declare FileWriter and BufferedWriter resources in one statement.

	try(	FileWriter fw = new FileWriter(file.getAbsoluteFile());
			BufferedWriter bw = new BufferedWriter(fw)){
		....		
	}catch (IOException e) {
		...
	}

Exception Types

Exceptions which can be detected or checked by compiler and need to be handled are called checked exceptions. Exception and it’s subclasses that are not subclasses of RuntimeException are used to created checked exceptions. For example, IOException and FileNotFoundException are used when input out failure occurs and file is not found respectively.

Exceptions, which can’t be determined by the compiler and occur due to programming errors such as NullPointerException, ClassCastException, IndexOutOfBoundsException, etc., are called unchecked exceptions. Unchecked exceptions are created using objects of RuntimeException and its sub classes. Unchecked exceptions should be prevented by proper coding, but you can catch this exception and provide handler.

Other type of exception is called Errors which have nothing to do with the application. Errors occur due to computing resources issues such memory, hardware malfunction, etc. Errors are indicated by using Error and its sub classes. You can catch this type of exceptions for report purpose.

Unhandled Checked Exceptions

If an uncheck exception is reported by the compiler for a method and you don’t want to handle it in the method, you can mention in the declaration of the method that the particular unchecked exception will be thrown from the method using throw keyword followed by comma separated list of exceptions. This way, the caller of the method is given the opportunity to handle it and take appropriate action.

For example, in the method getScannerForFile() below, instantiation of Scanner object causes file not found exception. The exception is not handled in the method instead method declaration specifies that it throws the exceptions.

public Scanner getScannerForFile(String fileNAME) throws FileNotFoundException{
	Scanner sc = null;
	File f = new File(fileNAME);		
	sc = new Scanner(f);
	return sc;
}

Throw Exceptions

You can define your own exceptions for you application and throw them when the exception conditions they are defined for occur.

For example, InvalidCouponException is a custom exception and gets thrown when a coupon doesn’t have discount info.

public void validateDiscount(String offer) 
		throws InvalidCouponException{
	boolean valid = false;
	char prevChar = ' ';
	for(char a : offer.toCharArray()) {
		if(a == '%' && Character.isDigit(prevChar)) {
			valid = true;
		}
		prevChar = a;
	}

	if(!valid) {
		throw new InvalidCouponException();
	}
}
public class InvalidCouponException extends Exception{
	private static final long serialVersionUID = 862845541176661808L;
	public String toString() {
		return "Invalid coupon not found discount %";		
	}
}

Exception Details

Throwable class which is parent of all types of exceptions has methods which can be used to get details about exception. You can use getStackTrace() method to get stack trace information and method printStackTrace() can be used to print stack trace.