开发者

How to simplify/reuse this exception handling code

I tend to write code like the following a lot:

BufferedWriter w = null; // Or any other object that throws exceptions and needs to be closed
try {
    w = new BufferedWriter(new FileWriter(file));
    // Do something with w
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (w != null) {
        try {
            w.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

It usually involves an object that throws exceptions and n开发者_开发问答eeds to be closed, and that closing it may also throw an exception.

I was wondering if the above code can be simplified or reused in any way.


If you don't want to write code for closing in finally block, you should have a look at Project Lombok

Instead of writing the normal

public class CleanupExample {
  public static void main(String[] args) throws IOException {
  InputStream in = new FileInputStream(args[0]);
  try {
    OutputStream out = new FileOutputStream(args[1]);
    try {
      byte[] b = new byte[10000];
      while (true) {
         int r = in.read(b);
         if (r == -1) break;
         out.write(b, 0, r);
      }
    } finally {
        out.close();
      }
  } finally {
     in.close();
    }
  }
}

With Lombok you can write

public class CleanupExample {
  public static void main(String[] args) throws IOException {
    @Cleanup InputStream in = new FileInputStream(args[0]);
    @Cleanup OutputStream out = new FileOutputStream(args[1]);
    byte[] b = new byte[10000];
    while (true) {
      int r = in.read(b);
      if (r == -1) break;
      out.write(b, 0, r);
    }
   }
 }

Much more readable, and it generates the correct way of closing the Stream. This works with all the Closeable interfaces


I usually put contents of your finally block in a helper. Like this

void close(Closeable c) {
    if (c != null) {
        try {
            c.close();
        } catch (IOException e) {
            // perform logging or just ignore error
        }
    }
}

Closeable interface is implemented by many classes (input streams, database connections, etc), so this is kinda general-purpose helper.


Yes, since java 1.5 there is a Closeable interface. You can have a static method that closes any Closeable type.

  public static void closeIO(Closeable closeable){
      if (closeable != null) {
        try {
            closeable.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


Java 7 is having try with resource support. Check this out for more information.

I am quoting the relevant text and a code example here:

with the new try-with-resource language feature in Java 7, you effectively declare your stream arguments as part of the try-construct, and the compiler generates code that manages those resources automatically and cleanly for you.

private static void customBufferStreamCopy(File source, File target) {
    try (InputStream fis = new FileInputStream(source);
        OutputStream fos = new FileOutputStream(target)){

        byte[] buf = new byte[8192];

        int i;
        while ((i = fis.read(buf)) != -1) {
            fos.write(buf, 0, i);
        }
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}


I tend to agree with others who offer a method taking a Closeable, but due to maintining very long lived programs, the solution I use is slightly different. Basically it takes an OutputStream to provide flexibility.

public class IOHandler {

  private IOHandler();

  public static void close(OutputStream out, Closeable c) {
    if (c != null) {
      try {
        c.close();
    } catch (IOException e) {
        out.print(c.printStackTrace().getBytes());
    }
  }

}

The main advantages of this is that you can call it in a variety of ways, removing the need for specialized utilities to handle logging exceptions to stderr, stdout, and files.

IOHandler.close(System.out, openFile);
IOHandler.close(System.err, openFile);
IOHandler.close(logFile, openFile);

Other than this one added feature, it's basically the same solution others have offered.


I find it is usually best not to have try catch and finally all in the same block. It is often better to have a try-catch block and a separate try-finally block.

try {
    BufferedWriter w = new BufferedWriter(new FileWriter(file)); // Or any other object that throws exceptions and needs to be closed
    try {
        // Do something with w
    } finally {
        w.close();
    }
} catch (IOException e) {
    e.printStackTrace();
}

This also avoids any need to null check w.


Write it in a method ...

BuffereWriter getMyWriter()
{

// your code....

return w;
}


A template method pattern can be applied here:

public class FileTemplate {
    public void write(File file, WriteCallback c) {
        BufferedWriter w = null; // Or any other object that throws exceptions and needs to be closed 
        try { 
            w = new BufferedWriter(new FileWriter(file)); 
            c.writeFile(w); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } finally { 
            if (w != null) { 
                try { 
                    w.close(); 
                } catch (IOException e) { 
                    e.printStackTrace(); 
                } 
            } 
        }
    }
}

public interface WriteCallback {
    public void writeFile(BufferedWriter w) throws IOException;
}

.

new FileTemplate().write(file, new WriteCallback() {
    public void writeFile(BufferedWriter w) { ... }
});
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜