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) { ... }
});
精彩评论