I don't know C#, but the purpose of a finally
block in Java-ish languages is to ensure that system resources are relinquished, especially if garbage collection is irregular. It's the same principle for all. Consider the block
InputStream is = new FileInputStream("foo.txt");
OutputStream os = new FileOutputStream("D:/nonexistent/directory/bar.txt");
// Throws a FileNotFoundException.
The variable is
is created successfully, and takes up system resources. Processes can only use a fixed number of file handles at a time. The variable os
is never created, and an exception is thrown, and bubbles up to the caller. In the process, is
goes out of scope, and becomes eligible for garbage collection.
However garbage collections are never guaranteed to happen, or they may happen at some indefinite time in the future. So, the system resources taken by is
may never be freed. This can be costly, or can crash the program if it happens enough times. So, finally
blocks were put into Java. Other languages have similar constructs. In C++, destructors are invoked deterministically. LISPy languages have unwind-protect
, but those are usually packaged in with-foo
macros.
In Java 6 and lower, one would do this:
try {
is = new FileInputStream("foo.txt");
os = new FileOutputStream("D:/nonexistent/directory/bar.txt");
// work...
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ignored) {}
}
if (os != null) {
try {
os.close();
} catch (IOException ignored) {}
}
}
You can't just call is.close()
because that might throw, and then os
will never be closed. You have to check for null
too. Sane people used Jakarta Commons-IO's IOUtils.closeQuietly()
methods to replace the block:
} finally {
IOUtils.closeQuietly(is);
IOUtils.closeQuietly(os);
}
But Java 7 introduced a better solution: try-with-resources. C# 4 probably came first with something similar, Microsoft being quicker on the uptake than Snoracle.
try (
is = new FileInputStream("foo.txt"),
os = new FileOutputStream("D:/nonexistent/directory/bar.txt")
) {
// work...
}