Try With Resources

Closing resources is an important best practice in all the languages, but most of the times it is forgotten by developers or implemented inappropriately. This article explains the actual purpose of closing resources and the newly introduced try-with-resources which made the job of developers much easy.

First of all, why do we need to close the connections? Take the FileInputStream/FileOutputStream classes. Once you have completed the file handling operations using these classes, you are required to close the connection. The reason is something related to the behavior of operating systems. Hard disk’s speed is much slower than processor, that’s why RAM is used in computers as an inter-mediator between the hard disk and the processor. For reading or writing purposes if processor directly access a file in the hard disk, the file accessing will take a lot of time and which will slow down the process. To solve this problem, operating system creates a virtual file in the RAM which is much similar to the file in the hard disk (if it is already there). All your read/write operations are performed on that virtual file and once you complete your taks the changes will be update to the actual file.


The virtual file will be created when you create a new FileInputStream or FileOuputStream and closed once you call the close method on those streams. Sometimes operating system may update the content of the virtual file to the actual file time by time. Such an update is totally determined by the operating system based on the size of the file and available resources on that time, but this is not guaranteed to happen always. Suppose if there are any modified content in the virtual file and if the operating system has not updated it to the file automatically, how can we inform the operating system to update the actual file? This is actually handled by the flush method available within the OutputStreams. Flush method is used to inform the operating system to update the content of virtual file to the actual file.

Now you might have another question… If we open a file for read only purposes, then why do we need to flush the stream? You are right! That is why, there is no flush() method inside the InputStream classes. The flush method is only for OutputStreams not for Inputstreams. Still we have one more question... If flush method can update to the persistence storage, what is the purpose of having a close method even inside InputStreams?

Updating the virtual file to an actual file is fine and you can guarantee that there are no data loss, BUT there are something more. Whenever you open a connection, operating system will allocate some resources for you. Once you have completed your task, you must release them to free the memory. If you have opened hundred to thousand connections, and if you forgot to close all of them, the result would be something serious like memory out of error. So regardless you are reading something or writing something, if you have opened a connection you need to close it.
If you are calling the close method of an OutputStream explicitly, a call for flush is unnecessary since implicitly the close will take care of flushing.

Closing resources is not just a matter with file system related operations only. Some database libraries might not save the data to database until you call the close method on the opened connection. If you are an Android developer, the problem would be even serious. Keeping a connection alive forever is more serious problem in mobile devices with limited resources than desktop computers. In an Android application if you forget to close a connection, you must be ready to face a runtime exception when you run your application.

Now look at this example which is used to write a text message to a text file using FileWriter object.
import java.io.*;

public class FileWriterDemo {
    public static void main(String[] args) {
        FileWriter writer = null;
        try {
         // Create a FileWriter object
            writer = new FileWriter("sample.txt");
            writer.write("Hello world!");
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
         // Check for null reference
            if (writer != null) {
                try {
                    writer.close(); // Close the connection
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }
}
The object creation, write method and close method all can throw IOException so there are two try catch blocks which make the code messy. There is another hidden problem in this code; developer can access the FileWriter object even after closing the connection. If it is not clear enough, look at this code.
import java.io.*;

public class FileWriterIllegalAccessDemo {
    public static void main(String[] args) {
        FileWriter writer = null;
        try {
            // Create a FileWriter object
            writer = new FileWriter("sample.txt");
            writer.write("Hello world!");
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            // Check for null reference
            if (writer != null) {
                try {
                    writer.close();   // Close the connection
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
      
        try {
            // IOException: Stream closed
            writer.write("End of file.");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}
The line writer.write("End of file."); is called after closing the connection and will throw an IOException. If there is a way to close the connection without writing more lines and a way to limit the scope of writer reference within the active zone of FileWriter, it would be much better. That feature was added in Java 1.7 version as try-with-resources. Now go through the following code. To compile this code you need JDK 1.7 or latest.
import java.io.*;

public class TryWithResources {
    public static void main(String[] args) {
        try (FileWriter writer = new FileWriter("sample.txt")) {
            writer.write("Hello world!");
        } catch (IOException ex) {
            ex.printStackTrace();
        } // No close statements
        // Cannot access writer here
    }
}
Obviously there are less number of lines and we have only one try-catch block. It makes the code more readable and the writer reference is local to the try block so you cannot access it outside of the try block. In this way Java guarantees that, there cannot be any illegal accesses after closing the connection. According to the try-with-resources standard, you can create any object that implements java.lang.AutoCloseable interface, as a resource inside the try-with-resources statement. If you are creating more than one resource, then you need separate them using semicolon as shown below.
import java.io.*;

public class TryWithMultiResources {
    public static void main(String[] args) {
     // Notice the semicolons
        try (FileWriter fw = new FileWriter("sample.txt");
         BufferedWriter writer = new BufferedWriter(fw);) {
            writer.write("Hello world!");
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}
Java 1.7 introduced two enhancements to try-catch-block. The try-with-resources is one of that enhancement, which we have discussed in this article. The second enhancement multi-catch block will be covered in another article.

Find the source codes at Git Hub.
Previous
Next Post »

Contact Form

Name

Email *

Message *