[关闭]
@linux1s1s 2017-08-09T10:53:34.000000Z 字数 4127 阅读 1944

Right way to Close InputStream and OutputStream in Java

Java 2016-01


For some unknown reasons many Java programmers are not very comfortable with IO package. I don't know why, but I have found them much more comfortable with java.lang and java.util than java.io. One possible reason of this could be that, writing IO code require a bit of C++ like programming, which involves doing clean-up, releasing resources once done etc. Since Java made coding a lot easier by taking care of memory management, unknowingly it also introduced bad practice of not releasing resource after use e.g. database connections, socket connection, files, directory, printers, scanners or any other scarce resource. The laziness of just doing work and forget everything is very easy, because of this many Java programmer never bother about doing clean-up. This habit is most visible in programmers who have never done system programming using C or C++. Since IO requires you to deal with streams, channels, and file descriptors, which need to be closed properly, Java developer find it uneasy to deal with. On other day, I asked one candidate to write code for copying content of one file to another without using copy() method or a third-party library. Though he managed to write the code, he made a common mistake, he was not closing streams properly. It's important to close streams, to release file descriptor held by this class, as its limited resource and used in both socket connection and file handling. A serious resource leak may result in file descriptor exception as well. Before moving ahead, let's see the part of the code candidate wrote for copying file from one directory to another directory in Java without using any third-party library.

  1. FileInputStream fis = null;
  2. FileOutputStream fos = null;
  3. try {
  4. fis = new FileInputStream("../input/fxrates.txt");
  5. fos = new FileOutputStream("../output/fxrates.txt");
  6. // code for reading from input stream and writing to output stream
  7. } finally {
  8. try {
  9. // He was careful to close streams in finally block, but it’s not complete // Can you spot error?
  10. if (fis != null)
  11. fis.close();
  12. if (fos != null)
  13. fos.close();
  14. } catch (IOException e) {
  15. System.out.println("Failed to close streams");
  16. }
  17. }

Most of his code is al-right and even better than many Java programmers. He was even careful to close streams in finally block, but he still made an error, which could cause resource leak in his Java program. Can you spot the error? Yes, output stream will not be closed if close() method of input stream will throw an Exception i.e. fos.close() will not even execute if fis.close() throws exception. This means file descriptor held by OutputStream will never release causing a resource leak in Java program. It's not uncommon, I have seen many such code, where developers has right intention to release resources by closing streams but fail to realize something equally important. Right way of closing stream is by closing them in their own try catch block, so that failure of closing one stream should not prevent calling close() on other stream. Here is the right way of closing InputStream and OutputStream in Java :

  1. InputStream is = null;
  2. OutputStream os = null;
  3. try {
  4. is = new FileInputStream("../input/fxrates.txt");
  5. os = new FileOutputStream("../output/fxrates.txt");
  6. //......
  7. } finally {
  8. try {
  9. if (is != null) is.close();
  10. } catch (IOException e) {
  11. //closing quietly}
  12. try {
  13. if (os != null) os.close();
  14. } catch (IOException e) {
  15. //closing quietly
  16. }
  17. }
  18. }

This code will not forget to call os.close() even if is.close() will throw IOException, which ensures that file descriptor held by OutputStream will be released. If you don't like so many try-catch and try-finally block or fed-up with verbosity of this program then you can also try Apache commons IO package. It provides a closeQuitetly() method to close streams quietly i.e. above finally block can be re-written by using IOUtils.closeQuietly() as following.

  1. try {...............
  2. } finally {
  3. IOUtils.closeQuietly( in );
  4. IOUtils.closeQuietly(os);
  5. }

closeQuitely() is an overloaded method for closing URLConnection, Closable, Socket, ServerSocket, Selector, InputStream, OutputStream, Reader and Writer classes. It is also null-safe, so don't check if Stream is null before calling this method. Here is source code of closeQuitely() method for closing InputStream :

  1. public static void closeQuietly(InputStream input) {
  2. try {
  3. if (input != null) {
  4. input.close();
  5. }
  6. } catch (IOException ioe) {
  7. // ignore
  8. }
  9. }

That's all on this post about right way of closing InputStream and OutputStream in Java. We have seen three examples of closing streams in Java and how combining close() call of two stream can cause resource leak in Java. Take away is always close streams in their own try-catch block. If you are using Apache commons IO in your project then take advantage of IOUtils.closeQuietly() method to reduce boiler-plate code.

Come from here

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注