use try-with-resources to close a Closeable - java

I have a Map<Key, Closeable> and if a key is removed from the map I want to close the Closeable. Normally I have something like:
Closeable c = map.remove(key);
c.close();
My Eclipse warns me "Resource 'c' should be managed by try-with-resource", so is it better just to write the following?
try (Closeable c = map.remove(key)) {}
In my special implementation I have a subclass of Closeable, where close() does not throw an IOException, so no exception handling is needed.

The point of try-with-resources is that:
The opening of the Closeable resource is done in the try statement
The use of the resource is inside the try statement's block
close() is called for you automatically.
So your suggested code:
try(Closeable c = map.remove(key)) {}
... doesn't satisfy the point of try-with-resource, since you're not using the resource inside the block. Presumably your Closeable is already open before this statement.
I'm guessing that you have some code whereby a bunch of resources are opened, work is done, then they are all closed by working through the map.
This is OK, and sometimes unavoidable. But it's cleaner, where possible, to have open() and close() in the same method, with the close() in a finally block, so that you can see at a glance that every open() has a corresponding close() and you can be sure that the close() is always called.
MyCloseable c = MyCloseable.open(...);
try{
// do stuff with c;
} finally {
try {
c.close();
} catch (IOException e) {
// ...
}
}
Once you've achieved that, try-with-resources just makes things neater:
try(MyCloseable c = MyCloseable.open(...)) {
// do stuff with c;
}
If your requirements mean you can't get open and close into the same methods, then just stick with an explicit close() and ignore the warning.

I would just ignore this warning, If you are managing close operation on your own, then just call close(). Empty try-with-resource looks weird.
Consider to extend Map so close operation will be performed automatically on remove:
public class CloseableMap<K,V extends Closeable> extends HashMap<K,V> {
#Override
public R remove(K key) {
V resource = super.remove(key);
if (resource != null) {
resource.close();
}
return resource;
}
}

Related

How to make sure resource is released, with nested object hierarchy?

I have code (simplified) like this:
class A {
B b = new B();
void close() {
b.close();
}
}
class B {
Closeable mustBeClosed = new Closeable() {
{
System.out.println("create");
}
#Override
public void close() {
System.out.println("close");
}
};
int n = 0 / 0;
void close() {
mustBeClosed.close();
}
}
//code
try (A a = new A()) {
//do something
}
How to guarantee mustBeClosed is released?
This likely happens when the object hierarchy is complex. Override finalize for B might not be a perfect solution.
Any best practice or principle against this issue?
A revised version looks like:
class B {
Closeable mustBeClosed;
B() {
try {
mustBeClosed = ...
//other initialization which might raise exceptions
} catch (throwable t) {
close();
throw t;
}
}
void close() {
if (mustBeClosed != null) {
try {
mustBeClosed.close();
} catch (Throwable t) {
}
}
//all other resources that should be closed
}
}
However this takes too much code and is far from elegant. What's more, it seems that all classes in the ownership hierarchy should follow the same style, which results lots of code.
Any advice?
Your problem is that try-with-resources won't (actually can't) call close() if the constructor throws an exception.
Any object construction that allocates a resource, and has the potential to fail during construction after the resource is allocated, must release that resource before the exception is cascaded up the call stack.
Two ways to fix that:
1) Make sure the resource allocation is the last action performed. In your case, that means move field n up before field mustBeClosed.
2) Handle the resource construction in the constructor, not in a field initializer, so you can catch any subsequent exception and release the resource again before re-throwing the exception, as your alternate solution shows.
However, you don't have to null-check in the close() method, because mustBeClosed will always be non-null if the object construction succeeds, and close() cannot be called if the object construction fails.
Use a wrapper method to close all Closeable instances gracefully.
closeGraceFully(Closeable c) { // call this guy for all instances of closeable
try{
c.close();
} catch(IOException ex) {
// nothing can be done here, frankly.
}
}
Then call this wrapper method. don't call close() directly. Don't use finalizers they are evil and will slow down your app.

The try-with-resources

I have a very simple question that seems to be stupid to me but yet asking .How BufferedReader call the close() method of Autocloseable interface. or how we can implement Autocloseable that call the close() automatically.
It's syntactic sugar. The javac compiler inserts the close() call into the compiled class at the end of the try block where the BufferedReader is declared, as you can see if you disassemble the class file with javap -c.
There's nothing you have to do in your own code besides implement AutoCloseable and provide a close() method. Java takes care of calling for you the close() method at the end of the try statement. Consider the following minimal demonstration:
class MyCloseable implements AutoCloseable {
public void close() { System.out.println("Close was called"); }
}
public class Ac {
public static void main(String[] args) {
try (MyCloseable mc = new MyCloseable()) {
}
}
}
$ java Ac
Close was called
try(AutoClosable x = open()) {}
is usually seen as short-hand version of
try {
Resource x = open();
} finally {
x.close();
}
There are two actual differences :
If both blocks throw, the autoclosable try statement will throw the exception from within the try statement, whereas the try...finally will throw the exception from the finally block. An exception from the other block would be suppressed.
In addition the exact behaviour is like this:
try(Autoclosable x = open) {
//do something
} do_close {
x.close();//not actually there - executed before catch and finally!
} catch (WhateverException e){
//catch an exception
} finally {
//finally do something
}
From the Oracle Docs:
"A try-with-resources statement can have catch and finally blocks just
like an ordinary try statement. In a try-with-resources statement, any
catch or finally block is run after the resources declared have been
closed."
So due to these two technical details it is not just syntactic sugar, but in practice it is used where formerly try...finally would have been used.
There is no actual way to imitate the behavior of try-with-resources for other interfaces than Autoclosable afaik. If you want to do some cleanup after a try you will have to either use finally or implement Autoclosable. Finalizers seem to do something similar, but actually they don't. I just mention them here to advise you not to use them.

try-with-resources fails to call close()

I am using the handy try-with-resources statement to close connections. This works great in most cases but only in one utterly simple method it does not work properly. Namely, here:
public boolean testConnection(SapConnection connection) {
SapConnect connect = createConnection(connection);
try ( SapApi sapApi = connect.connect() ) {
return ( sapApi != null );
} catch (JCoException e) {
throw new UncheckedConnectionException("...", e);
}
}
The sapApi object is non-null, the method returns true, but the close() method of sapApi is never called. I now resorted to use a finally block which works fine. But this is quite puzzling. The Java byte code also contains a call to close. Has anyone seen this behavior before?
Edit to clarify the situation:
This is the SapApi, it implements AutoCloseable, of course.
class SapApi implements AutoCloseable {
#Override
public void close() throws JCoException {
connection.close(); // this line is not hit when leaving testConnection(..)
}
..
}
The following is another method in the same class as testConnection(..). Here SapApi.close() is called before returning.
#Override
public List<Characteristic> selectCharacteristics(SapConnect aConnection, InfoProvider aInfoProvider) {
try (SapApi sapi = aConnection.connect()) {
return sapi.getCharacteristics(aInfoProvider);
} catch ( Exception e ) {
throw new UncheckedConnectionException(e.getMessage(), e);
}
}
Edit 2:
This is SapConnect.connect():
SapApi connect() {
try {
... // some setup of the connection
return new SapApi(this); // single return statement
} catch (Exception e) {
throw new RuntimeException(e);
}
}
SapApi has no subclasses. There is just one implementation with the close method as above. In particular, there is no empty close().
In order for close() to be called, SapApi must implement AutoCloseable interface, but since we are talking about connection, it is more appropriate that you SapApi will implement Closable interface which throws IOException.
Read this:
http://tutorials.jenkov.com/java-exception-handling/try-with-resources.html
I do not know what you mean by
This works great in most cases
1 That normally the SapApi is closed when used in try-with-resources
or
2 That it normally works for resources other than SapApi
I am answering on the assumption of number 2.
Try-with-resources will only work in Java 7 for resources that implement the AutoCloseable interface. So my first advice would be to for you to check the API for SapConnect and SapApi (whatever they are) to determine if that is the case.
One guess: maybe connect returns a child or proxy class of SapApi. With close overridden to do nothing if no change was made, only otherwise call super.close().
I'll give it as an answer, as AutoCloseable works even if no method is called.

Why is try-with-resources catch block selectively optional?

I read that the catch block in try-with-resources is optional.
I've tried creating a Connection object in a try-with-resources block, with no subsequent catch block, only to get compiler error from eclipse:
"Unhandled exception type SQLException thrown by automatic close() invocation."
Since every resource that can be used in try-with-resources implements AutoCloseable, and so potentially throws an exception upon invocation of the close() method, I don't understand how the catch clause is optional, given that it's not allowing me to skip catching the exception from close().
Is there some special requirement that the specific implementation of AutoCloseable not directly declare any exception thrown in its close() method? (e.g. override AutoCloseable's close() throws Exception with a close() which does not throw any Exception)?
..or is this possibly just an eclipse issue?
Edit: Here's the simplest code fragment that still triggers the problem:
try (Connection con = dataSource.getConnection()) {
/*...*/
}
Thoughts on whether or not this is related to the use of a JNDI DataSource?
Thanks in advance.
It is optional if close() is not able to throw a checked exception. However, if close() can, then a checked exception would need to handled in a normal fashion, either with a catch block, or by throwing from the method that try-with-resources block is in.
More details are in JLS 14.2.3
14.20.3.2. Extended try-with-resources
A try-with-resources statement with at least one catch clause and/or a finally clause is called an extended try-with-resources statement.
The meaning of an extended try-with-resources statement:
try ResourceSpecification
Block
[Catches]
[Finally]
is given by the following translation to a basic try-with-resources statement nested inside a try-catch or try-finally or try-catch-finally statement:
try {
try ResourceSpecification
Block
}
[Catches]
[Finally]
The effect of the translation is to put the resource specification "inside" the try statement. This allows a catch clause of an extended try-with-resources statement to catch an exception due to the automatic initialization or closing of any resource.
Furthermore, all resources will have been closed (or attempted to be closed) by the time the finally block is executed, in keeping with the intent of the finally keyword.
Thoughts on whether or not this is related to the use of a JNDI DataSource?
Yes, it is.
In the example try-with-resourses block you've provided, it is necessary to catch the exception and handle, or throw from the method the block is in, because SQLException is a checked exception.
You could just be throwing the exception up (or catching it in another try-catch block):
private static void test() throws IOException {
try(InputStream is = new FileInputStream("test.txt")) {
while(is.read() > -1) {
}
} finally {
// Will get executed, even if exception occurs
System.out.println("Finished");
}
}
You can create an AutoClosable that does not require an explicit catch-block by declaring your AutoClosable's close() method without any Exception or with a RuntimeException. Without any Exception it is clear that no catch-block is required. Further, the compiler does not statically check for a RuntimeException to be catched (in contrast to checked Exceptions).
Example:
public class AutoClosableDemo
{
public static void main( final String[] args )
{
try (MyAutoCloseable1 mac1 = new MyAutoCloseable1())
{
System.out.println( "try-with-resource MyAutoCloseable1" );
}
try (MyAutoCloseable2 mac2 = new MyAutoCloseable2())
{
System.out.println( "try-with-resource MyAutoCloseable2" );
}
// The following is not allowed, because
// "Unhandled exception type Exception thrown by automatic close() invocation on mac3"
// try (MyAutoCloseable3 mac3 = new MyAutoCloseable3())
// {
// System.out.println( "try-with-resource MyAutoCloseable13" );
// }
System.out.println( "done" );
}
public static class MyAutoCloseable1 implements AutoCloseable
{
#Override
public void close()
{
System.out.println( "MyAutoCloseable1.close()" );
}
}
public static class MyAutoCloseable2 implements AutoCloseable
{
#Override
public void close() throws RuntimeException
{
System.out.println( "MyAutoCloseable2.close()" );
}
}
public static class MyAutoCloseable3 implements AutoCloseable
{
#Override
public void close() throws Exception
{
System.out.println( "MyAutoCloseable3.close()" );
}
}
}
You could check the JLS but there is actually a relatively easy reasoning why this is the only correct way the language should behave.
The main rule of checked exceptions is that any checked exception declared by a method must be handled, either by catching it or letting the calling method throw it.
The try-with-resources always (implicitly) calls the close method.
So if the specific close method of the AutoClosable you use (determined by the type declared in try) declares to throw a checked exception such as a SQLException you do need to handle this checked exception somewhere, otherwise it would be possible to violate the rule!
If the close method does not declare that it throws a checked exception, the rule is not violated and you do not need to handle a checked exception for implicitly calling the close method. It is actually a compilation failure if you do try to catch a checked exception that is never declared to be thrown.
Not every Java class (!) throws an exception. Sometimes you just want to use a try-with-resources to use the auto-close feature, and nothing else.
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
if (br != null) br.close();
}
This the catch is optional because readLine() doesn't throw a (checked) exception.
Yes, close() could throw an exception, but the try-with-resources handles that too.
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
So this try-with-resources doesn't need a catch.

What is the best way to emulate try-with-resources in Java 6?

It turns out that almost nobody closes resources in Java correctly. Programmers either do not use try-finally block at all, or just put resource.close() in finally which is also incorrect (because Throwable from close() can shadow Throwable from try block). Sometimes they put something like IOUtils.closeQuietly() with is only correct for InputStream, but not for OutputStream. try-with-resources solves all of these problems but there are still huge number of projects written in Java 6.
What is the best way to emulate try-with-resources in Java 6? Now I use Guava Closer, which is better than nothing but still much uglier than try-with-resources. Also, there is a pattern called a loan-pattern, but the absence of lambdas in Java makes this pattern very cumbersome. Is there a better way?
I've found a good replacement for try-with-resources. It uses Lombok library with annotation processing:
#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);
}
However, it doesn't handle exception correctly. This bug is more than 1 year old and still is not closed: https://code.google.com/p/projectlombok/issues/detail?id=384
Though anonymous class is quite verbose, it's still acceptable in java land
new TryWithResource<InputStream>(){
protected InputStream init() throws Exception {
return new FileInputStream("abc.txt");
}
protected void use(InputStream input) throws Exception{
input.read();
}
};
----
abstract class TryWithResource<R>
{
abstract protected R init() throws Exception;
abstract protected void use(R resource) throws Exception;
// caution: invoking virtual methods in constructor!
TryWithResource() throws Exception
{
// ... code before
R r = init();
use(r);
// ... code after
}
}
If your only problem with IOUtils.closeQuietly is that it ignores exceptions on OutputStreams, then you can either simply call close() on them, or create your own utility class which automatically treats the two differently, like this:
public static void close(Closeable resource)
{
try
{
resource.close();
}
catch(Exception e)
{
//swallow exception
}
}
public static void close(OutputStream o)
{
//throw any exceptions
o.close();
}
The correct overloaded method will be selected at compile time in all common situations, although if you're passing OutputStreams around as Closeables then you'll have to change this to do a dynamic instanceof check to make sure OutputStreams always throw exceptions.

Categories