简体   繁体   中英

Is using try-with-resources without a new object instance bad form?

Generally I've always seen try-with-resources used to allocate a new object instance whose close() method is invoked as it goes out-of-scope.

As far as I can tell, creating a new object is not a requirement and the try-with-resources syntax simply needs a local variable to call close() on when that goes out-of-scope. Therefore you can use it to control "paired operations" such as allocating something from a pool and making sure it is returned.

For example, MyHandle below shows how to release a pooled instance when you no longer need it:

// init
class MyHandle implements AutoCloseable {
    boolean inUse = false; 
    public MyHandle allocate() {
        inUse = true;
        return this;
    }

    public void close() {
       inUse = false;
    }
}

MyHandle[] pool = new MyHandle[POOL_SIZE];
for (int i = 0; i < pool.length; i++) {
    pool[i] = new MyHandle(i);
}

// allocate
MyHandle allocateFromPool() {
    for (int i = 0; i < pool.length; i++) {
        if (!pool[i].inUse)
            return pool[i].allocate();
    }
    throw new Exception("pool depleted");
}

// using resources from the pool

try (MyHandle handle = allocateFromPool()) {
   // do something
}
// at this point, inUse==false for that handle...

Is this considered bad form?

EDIT: I guess I'm asking if there's better alternatives to building this sort of logic, or if there's some major drawback when going with the approach above. I find that using this in a library makes for a clean API.

EDIT 2: Please disregard problems in the code example, I wrote it inline in the SO text box to make my question clear with some sort of example. Obviously it's not real code! :)

The try-with-resource syntax is intended as a syntactic sugaring to allow you to make sure you dispose an object, whatever the disposal logic would be. In your case, it's returning the object to the pool. There's absolutely nothing wrong with using try-with-resource like this. It may not be the most common usecase for it, but it's definitely a valid one.

Under the covers, most resources (eg File Descriptors) are effectively allocated from a pool by the Operating System, and then returned to the pool when closed.

Using try-with-resources in this way is perfectly valid.

NB your code example has significant threading issues though, but I assume the necessary thread safety has been removed for clarity in the question. I mention it only because people should NOT copy your code and use it in an implementation.

Nothing wrong with try-with-resources like that. But in your case i would worry about accidential reusing closed handles that have been reopend from another thread.

A little indirection would solve that problem, return MyHandleWrapper instead of the direct access to MyHandle (allocateFromPool will return a new instance of MyHandleWrapper). It will not! solve all the other threading issues.

public class MyHandleWrapper extends MyHandle {
    private MyHandle handle;
    private boolean closed;

    public void close() {
        if(!closed){
            handle.inUse = false;
        }
        closed = true;
    }

    public void read() {
        if (closed) {
            throw new IllegalStateException("Already closed");
        }
        handle.read();
    }
}

Basically you keep the information if the handle was closed in MyHandleWrapper. You guard any state changing access to handle with that flag, if necessary throw appropriate exceptions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM