Consider the following code:
try (Transport transport = session.getTransport("smtp")) {
transport.connect();
} catch (MessagingException ignored) {}
What if, for some reason the auto-close fails? That might leave internally some file handler open (maybe not with SMTP but in general)
So is it correct to say that this code is prone to a resource/memory leak?
If the answer's yes, then what should a program do in such case?
The answer is 'theoretically, yes, pragmatically, no'. In the sense that:
So is it correct to say that this code is prone to a resource/memory leak?
If this is 'yes', then
If the answer's yes, then what should a program do in such case?
There is absolutely nothing you can do in this hypothetical, silly case.
Hence why it's pragmatically speaking no.
The code you wrote is syntax sugar. It's the same as this:
try {
Transport transport = session.getTransport("smtp");
try {
transport.connect();
} finally {
try {
transport.close();
} catch (Throwable t) {
if (we got here because the try block threw) {
theExceptionThatGotUsHere.addSuppressed(t);
throw theExceptionThatGotUsHere;
} else {
throw t;
}
}
}
} catch (MessagingException ignored) {}
You see why java has syntax sugar for that mess. In essence, it just does the same thing we used to do, with the one upside that if close()
throws an exception, java takes some pains to ensure this does not end up confuscating the exception thrown by the main body. Generally if the flow goes:
close()
on an OutputStream
that is already tainted and that has already thrown. This, itself, also throws.Hence, perhaps, it's essentially as simple as:
try {
Transport transport = session.getTransport("smtp");
try {
transport.connect();
} finally {
transport.close();
}
} catch (MessagingException ignored) {}
So, how can this fail? Simple: If close()
itself can no longer close the resource.
However:
finally
block, but that's with try-with-resources already does.Specifically, the close() may fail, but what they won't do, is cause a resource/memory leak even if they fail. What DOES happen is the following:
close()
, this is important in particular for output streams, where close()
throwing cannot safely be ignored, it means not all data is guaranteed to have arrived where you sent it, you should handle an exception in an output stream's close() call no different than in a write call().close()
on this.close()
call cleans up resources (releases OS-level file handles, that sort of thing), and then throws the exception, to ensure you know that the write did not necessarily succeed.