Posted by & filed under java.

Because Java has a Garbage collector and you don’t know for sure when your object will be destroyed it is tricky to do proper resource management, in comparison with C++ where objects are created on the stack or you control their lifecycle manually by new/delete operator.

To help you deal with that, the finally block was introduced. Assume you have some kind of resource:

package com.binarybuffer.tests.trycatch;

/**
 * Class that simulates some resource which needs to be released.
 * @author kenota
 *
 */
public class Resource {
	private String name;
	private boolean resourceAllocated;

	public Resource(String name) {
		this.name = name;
		resourceAllocated = true;

		System.out.println(this +  " allocated");
	}

	public String toString() {
		StringBuilder sb = new StringBuilder();

		sb.append("Resourse{name=")
		.append(name)
		.append("}");

		return sb.toString();
	};

	/**
	 * Simulates release of resource.
	 * @param throwException if set to true, SomeBadException will be thrown
	 */
	public void release(boolean throwException) {
		if (throwException) {
			throw new SomeBadException(this + " exception during release()");
		}
		if (resourceAllocated) {
			resourceAllocated = false;
			System.out.println(this + " was released");
		} else {
			System.out.println(this + " resource was already released. Nothing to do");
		}
	}

	public void release() {
		release(false);
	}

	/**
	 * Simulates some work for specified time
	 * @param ms long time in ms to simulate work
	 * @param throwException if true, SomeBadException will be thrown
	 */
	public void doWork(long ms, boolean throwException) {
		if (throwException) {
			throw new SomeBadException("Exception in Resource.doWork()");
		}
		try {
			Thread.sleep(ms);
		} catch (InterruptedException e) {
			System.out.println("InterruptedException");
		}
	}

	public void doWork(long ms) {
		doWork(ms, false);
	}

	@Override
	protected void finalize() throws Throwable {
		try {
			release();
		} finally {
			super.finalize();
		}
	}
}

You can use this resource like this:

private static void workWithResource() {
	System.out.println("Entering workWithResource");
	Resource dbConnection = null;

	try {
		dbConnection = new Resource("DBConnection");
		dbConnection.doWork(ONE_SEC, true);
	} finally {
		if (dbConnection != null)
			dbConnection.release();
	}

	System.out.println("Leaving workWithResource");
	return;
}

Running this code will produce the following output:

Entering workWithResource
Resourse{name=DBConnection} allocated
Exception Exception in Resource.doWork() created
Resourse{name=DBConnection} was released
Exception in thread "main" com.binarybuffer.tests.trycatch.SomeBadException: Exception in Resource.doWork()
	at com.binarybuffer.tests.trycatch.Resource.doWork(Resource.java:57)
	at com.binarybuffer.tests.trycatch.TryCatchExample.workWithResource(TryCatchExample.java:28)
	at com.binarybuffer.tests.trycatch.TryCatchExample.main(TryCatchExample.java:17)

So here we are simulating some work with a resource which generates an exception. Because we using a finally block we release precious resource before exception is thrown further. Everyone is happy. Now let me explain what you should keep in mind when using finally. You must remember that the finally block will always be executed. (Well, almost always. I will explain later)

What does that mean?

Exception hiding.

Consider following code.

private static void hiddenException() {
	System.out.println("Entering hiddenException");
	Resource dbConnection = null;

	try {
		dbConnection = new Resource("DBConnection");
		dbConnection.doWork(ONE_SEC, true);
	} finally {
		if (dbConnection != null)
			dbConnection.release(true);
	}
	System.out.println("Leaving hiddenException");
}

What is happening here? We are simulating work with a resource again. But two exceptions will be generated: first inside the doWork() method and the second one when we are trying to release the resource in the finally block. Which exception will be thrown to calling code? Lets run and see:

Entering hiddenException
Resourse{name=DBConnection} allocated
Exception Exception in Resource.doWork() created
Exception Resourse{name=DBConnection} exception during release() created
Exception in thread "main" com.binarybuffer.tests.trycatch.SomeBadException: Resourse{name=DBConnection} exception during release()
	at com.binarybuffer.tests.trycatch.Resource.release(Resource.java:35)
	at com.binarybuffer.tests.trycatch.TryCatchExample.hiddenException(TryCatchExample.java:47)
	at com.binarybuffer.tests.trycatch.TryCatchExample.main(TryCatchExample.java:18)

Two exceptions are thrown. One in doWork and one in release. But you will never see the original exception anywhere. It is now completely hidden and forgotten like the days when Sun was not owned by Oracle :)

Thats why, code in the finally block should be exception safe:

private static void notSoHiddenException() {
	System.out.println("Entering notSoHiddenException");
	Resource dbConnection = null;

	try {
		dbConnection = new Resource("DBConnection");
		dbConnection.doWork(ONE_SEC, true);
	} finally {
		try {
			if (dbConnection != null)
				dbConnection.release(true);
		} catch (Throwable t) {
			// Log it somwhere
			System.out.println("Exception while releasing resource " + t.getMessage());
		}
	}

	System.out.println("Leaving notSoHiddenException");
}

And here is the output:

Entering notSoHiddenException
Resourse{name=DBConnection} allocated
Exception Exception in Resource.doWork() created
Exception Resourse{name=DBConnection} exception during release() created
Exception while releasing resource Resourse{name=DBConnection} exception during release()
Exception in thread "main" com.binarybuffer.tests.trycatch.SomeBadException: Exception in Resource.doWork()
	at com.binarybuffer.tests.trycatch.Resource.doWork(Resource.java:57)
	at com.binarybuffer.tests.trycatch.TryCatchExample.notSoHiddenException(TryCatchExample.java:60)
	at com.binarybuffer.tests.trycatch.TryCatchExample.main(TryCatchExample.java:19)

As you can see, the exception in Resource.doWork() is thrown outside the method.

Do not use return in finally block

Return in the finally block will also hide all exceptions and will always execute:

private static boolean returnFromFinally() {
	System.out.println("Entering returnFromFinally");
	Resource dbConnection = null;

	try {
		dbConnection = new Resource("DBConnection");
		return true;
	} finally {
		return false;
	}
}

The code above will produce the following output:

Entering returnFromFinally
Resourse{name=DBConnection} allocated
Result of returnFromFinally(): false

And if any code inside try { } block throws an exception, you wont see it anywhere at all, like it never happened.

Ways to avoid executing finally block

Remember I told you that the finally block almost always executes? How can you prevent it from execution? Well, first option is old, rock solid, System.exit():

private static void avoidFinally() {
try {
	System.out.println("In try");
	System.exit(0);
	} finally {
		System.out.println("In finally()");
	}
}

This will never print “In finally()”.

Second way is to call the deprecated suspend() method on a thread  and never call resume():

private static void avoidFinallyBySuspend() {
	System.out.println("Entering avoidFinallyBySuspend");
	Thread t = new Thread(new Runnable() {

		@Override
		public void run() {
			try {
				System.out.println("Thread going to sleep");
				Thread.sleep(ONE_SEC * 5);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} finally {
				System.out.println("Finally in thread executed");
			}
		}
	});

	t.start();

	try {
		Thread.sleep(ONE_SEC); // let it run for some time
		System.out.println("Stoping thread using the Force");
		t.suspend();
		t.join(ONE_SEC * 5);

	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}

	System.out.println("Leaving avoidFinallyBySuspend");
}

Output:

Entering avoidFinallyBySuspend
Thread going to sleep
Stoping thread using the Force
Leaving avoidFinallyBySuspend

This trick does not work with thread’s deprecated stop() method:

private static void avoidFinallyByStop() {
	System.out.println("Entering avoidFinallyByStop");
	Thread t = new Thread(new Runnable() {

		@Override
		public void run() {
			try {
				while (true) ;
			} finally {
				System.out.println("Finally in thread executed");
			}

		}
	});

	t.start();

	try {
		Thread.sleep(ONE_SEC); // let it run for some time
		System.out.println("Stoping thread using the Force");
		t.stop();
		t.join(ONE_SEC * 5);
	} catch (InterruptedException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}

	System.out.println("Leaving avoidFinallyByStop");
}

Output:

Entering avoidFinallyByStop
Stoping thread using the Force
Finally in thread executed
Leaving avoidFinallyByStop

As you can see, finally is executed in the thread. Interesting.
So the only way to avoid execution of the finally block is to interfere with code execution flow. Otherwise, finally will be always executed.

One Response to “Things you need to remember when using finally in Java”

Leave a Reply

  • (will not be published)