I've just started getting back into Java recently and never had an opportunity to use try-with-resources
. On the surface it looks great as it can cut down on code, but under the hood is it more or less expensive of an operation than the traditional try-catch
? I know try-catch
already is an expensive operation, hence my curiosity.
I gave both types a simple test and didn't notice much of a difference at all:
long startTime = System.currentTimeMillis();
ArrayList<String> list = null;
try (Scanner sc = new Scanner(new File("file.txt"))) {
list = new ArrayList();
while (sc.hasNext()) {
list.add(sc.next());
}
} catch (Exception ex) {
System.err.println("Error: " + ex.getMessage());
} finally {
long endTime = System.currentTimeMillis();
System.out.println("The program completed in " + (endTime - startTime) + " ms");
}
long startTime = System.currentTimeMillis();
ArrayList<String> list = null;
Scanner sc = null;
try {
sc = new Scanner(new File("file.txt"));
list = new ArrayList();
while (sc.hasNext()) {
list.add(sc.next());
}
} catch (Exception ex) {
System.err.println("Error: " + ex.getMessage());
} finally {
sc.close();
long endTime = System.currentTimeMillis();
System.out.println("The program completed in " + (endTime - startTime) + " ms");
}
Both resulted in a time of 15-16ms - no real noticeable difference at all. But admittedly this is a very small test example.
My question again: Under the hood is try-with-resources
more or less expensive than a traditional try-catch
?
It's apples and oranges. An ARM (automatic resource management, or try-with-resources) block does more than the old-fashioned try-catch-finally block that you show. That's because it generates the code to handle exceptions that are thrown in resource closure with the suppression mechanism. (A related answer discusses this in some detail.)
If you are writing new code, use an ARM block. It is easier to read, maintain, and it does more. Unless you are running in a tightly constrained environment (like a smart card), these advantages are likely to outweigh the cost of a few extra byte codes.
Try-catch-finally and try-with-resources have essentially the same performance because under the covers they generate essentially the same bytecode.
However, your second version (try..catch..finally) is not quite formulated correctly as it could (in theory) lead to an undesirable NullPointerException
when sc.close()
is called. If the act of constructing a Scanner
causes an exception to be thrown then sc
will not be assigned and will be null
.
You should construct the Scanner outside of the try..finally
and change this:
Scanner sc = null;
try {
sc = new Scanner(new File("file.txt"));
...
to:
Scanner sc = new Scanner(new File("file.txt"));
try {
...
Alternatively, you should check that sc != null
in the finally
clause before calling sc.close()
. This won't be necessary if you create the scanner outside of the try..finally, so I would recommend you do that.
To do the same job as try-with-resources, you will also need to put a second try..catch
around the sc.close()
with an empty catch block, to ignore any exceptions thrown during close. If you do that, I suppose you don't need to worry so much about the null check.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With