Introduction:
The ‘finally’ keyword is a part of try/catch block. But it has significant importance from memory management point of view. This article will not discuss about the normal flow of exception handling but it will explain the implementation of ‘finally’ keyword to prevent memory leak.
The finally keyword is an integral part of java exception handling mechanism. The finally block ensures that the JVM will execute the code written within it even if there is an exception in the code. The finally construct helps to maintain the initial state of the object and to clean up the non memory resources. Normally a finally block is used to ensure the following:
- An Input Output stream is closed
- A database connection is closed
Both of these scenarios lead to memory or resource leaks if they are not closed. The finally is useful for more than just exception handling, it allows the programmer to avoid having cleanup code accidentally bypassed by a return, continue, or break. It is always a good practice to put the cleanup code within a finally block, even when no exceptions are anticipated.
Usage:
Let us consider the following code:
Listing 1: Sample code without finally block
import java.io.FileOutputStream ; import java.io.IOException ; import java.io.ObjectOutputStream ; import java.text.DateFormat ; import java.text.ParseException ; import java.text.SimpleDateFormat ; import java.util.Date ; import com.home.markerDemo.Employee ; public class SerializeDemo { public SerializeDemo () { } public static void main( String [] args ) { Employee employee = new Employee () ; employee.setFirstName( " John " ) ; employee.setLastName( " Smith " ) ; employee.setDepartment( " Technical " ) ; employee.setEcode( 1234 ); try { String dojStr = " 1971-07-15 " ; DateFormat df = new SimpleDateFormat ( " yyyy-MM-dd " ) ; Date dojDate = null ; dojDate = df.parse ( dojStr ) ; employee.setDateOfJoining( dojDate ) ; FileOutputStream fileOut = new FileOutputStream ( " employee.ser " ) ; ObjectOutputStream out = new ObjectOutputStream ( fileOut ) ; out.writeObject ( employee ) ; out.close () ; fileOut.close () ; } catch ( IOException i ) { i.printStackTrace () ; } catch ( ParseException e ) { e.printStackTrace () ; } } }
As we can see here the Object output stream and File Output stream are closed within the try block. So in case there is an exception in the following line code:
out.writeObject ( employee );
The code will terminate at this point. The control will move to the exception block and these two objects will remain open for ever. This will lead to resource leakage. Now let’s change the above code as under:
Listing 2: Sample code with finally block
import java.io.FileOutputStream ; import java.io.IOException ; import java.io.ObjectOutputStream ; import java.text.DateFormat ; import java.text.ParseException ; import java.text.SimpleDateFormat ; import java.util.Date; import com.home.markerDemo.Employee ; public class SerializeDemo { public SerializeDemo () { } public static void main ( String [] args ) { Employee employee = new Employee () ; employee.setFirstName ( " John " ) ; employee.setLastName ( " Smith " ) ; employee.setDepartment ( " Technical " ) ; employee.setEcode ( 1234 ) ; FileOutputStream fileOut = null ; ObjectOutputStream out = null ; try { String dojStr = " 1971-07-15 " ; DateFormat df = new SimpleDateFormat ( " yyyy-MM-dd " ) ; Date dojDate = null ; dojDate = df.parse ( dojStr ) ; employee.setDateOfJoining ( dojDate ) ; fileOut = new FileOutputStream ( " employee.ser " ) ; out = new ObjectOutputStream ( fileOut ) ; out.writeObject ( employee ) ; } catch ( IOException i ) { i.printStackTrace () ; } catch ( ParseException e ) { e.printStackTrace () ; } finally { try { out.close () ; fileOut.close () ; } catch ( IOException e ) { e.printStackTrace () ; } } } }
The above piece of code is exactly the same as the earlier version except for the fact that the resources Object Output stream and File Output Stream are closed within a finally block. This ensures that even if there is an exception while executing:
out.writeObject ( employee );
The Object Output Stream and the File Output Stream are closed. This code is much more reliable as this ensures that there is no resource leakage.
The finally block ensures the close method is executed whether or not an exception is thrown from within the try block. Thus, the close method is guaranteed to be called before the method exits. As a developer we are then sure that both the file output stream and the object output stream are closed. Thus there is no possibility of a resource leakage. In a situation where the exception has occurred the finally block executes after the catch block is executed. In case there is no exception, the finally block is execute right after the try block thus ensuring that the resources are released.
The finally block must be used in conjunction with a try or try/catch block. In fact, there is no way to exit a try block without executing it’s finally block. If the finally block exists, it always executes. If the code executes System.exit (0), then the code will exit without executing the finally block in all other situations the finally block is execute without fail.
How to Use the finally block:
Approach 1
If a method throws all the exception, then it is advised to use the finally block without any catch block.
Listing 3: A normal try and finally block
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public final class SimpleFinally { public static void main(String... aArgs) throws IOException { simpleFinally(" C:\\Temp\\test.txt "); } private static void simpleFinally(String aFileName) throws IOException { BufferedReader reader = new BufferedReader(new FileReader(aFileName)); try { // Any exception in the try block will cause the finally block to // execute String line = null; while ((line = reader.readLine()) != null) { // logic to process the line... } } finally { reader.close(); } } }
Approach 2:
If a method handles all of the checked exceptions which could be thrown from its implementation, then we can use a nested a try..finally block within a try..catch block. This approach becomes useful when they finally block also throws the same exceptions as the rest of the code. This behavior is commonly used in case of io operations. Though this approach looks slightly complicated, but is the better approach when compared to other approaches:
Listing 4: Using the try ... finally within a try ... catch block
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.logging.Logger; public final class NestedFinally { public static void main(String... aArgs) { nestedFinally("C:\\Temp\\test.txt"); } private static void nestedFinally(String aFileName) { try { BufferedReader reader = new BufferedReader( new FileReader ( aFileName ) ); try { String line = null; while ((line = reader.readLine()) != null) { // logic to process the line... } } finally { reader.close(); } } catch (IOException ex) { fLogger.severe("Problem occured : " + ex.getMessage()); } } private static final Logger fLogger = Logger.getLogger(NestedFinally.class .getPackage().getName()); }
Approach 3:
This is the traditional approach using the try ... catch ... finally as explained in Listing 2.
Conclusion:
We have already discussed different approaches in try-catch-finally block. The ‘finally’ keyword is generally considered to be a part of try-catch block. But it has other significant implementations also. As we all know memory leak is a major issue in application programming. So preventing memory leak is considered to be an important aspect in design. The power of ‘finally’ keyword is used in this area also. To conclude the discussion we can keep the following points in mind.
- The finally block ensures that the code written within it will execute even when there is an exception
- Finally block can be used as try ... finally or try ... catch ... finally