Search code examples
javaraiitry-with-resources

RAII design pattern in Java


Coming from a C++ background, I am a huge fan of the RAII pattern. I have used it extensively to handle memory management and lock management along with other use cases.

With Java 1.7 I see that i can use the try-with-resources pattern to create a RAII pattern.

I created a sample application using RAII and it works, but I see compiler warnings from java.

Sample Application

try(MyResource myVar = new MyResource(..))
{
    //I am not using myVar here 
}

I get the following errors

warning: [try] auto-closeable resource node is never referenced in body of corresponding try statement

I understand the warning, it is implying that I should have used the variable inside the try block, which I don't really need to do all the time.

Looking at this I am assuming that Java doesn't really have true support for RAII and I might have misused the feature which was only for Resource Management and not exactly a RAII equivalent in C++.

Couple of questions:

  1. Is my understanding correct?
  2. How risky is it to ignore these warnings?
  3. How do I ignore these warnings through ant?
  4. Is there a simple way for me to overcome this?

for 4 i am thinking of splitting the constructor call into a simpler constructor and a instance method like this

try(MyResource myVar = new Resource())
{
   myvar.Initialize()
   ....

}

Which solves the compiler problems but takes the essence out of the RAII like design.


Solution

  • 1. Is my understanding correct?

    More or less. Yes, you can use try-with-resources this way and yes, it is semantically comparable to RAII. The difference is there is no destruction or deallocation, only a method call.

    It's uncommon to find objects written just to wrap some resource management logic e.g.:

    import java.util.concurrent.locks.Lock;
    
    public class Guard implements AutoCloseable {
        private final Lock lock;
    
        public Guard(Lock lock) {
            this.lock = lock;
            lock.lock();
        }
    
        @Override
        public void close() {
            lock.unlock();
        }
    }
    
    try(Guard g = new Guard(myLock)) {
        // do stuff
    }
    

    If you're working with other programmers, you might have to explain what it means to a few people but I don't personally see a problem with it if it floats your boat.

    What I wouldn't recommend is writing weird code like

    try(AutoCloseable a = () -> lock.unlock()) {
        lock.lock();
        // do stuff
    }
    

    which is sure to generate WTFs in code review.

    2. How risky is it to ignore these warnings?

    Not risky. The warning is really just a notification. You know, in case you didn't know about it.

    To get rid of the warning you could try:

    try(@SuppressWarnings("unused")
        MyResource myVar = new MyResource())
    

    Or maybe see also 'How do you get *ant* to not print out javac warnings?'.

    An IDE should give you the option to suppress a particular warning either globally or only for a single statement (without the annotation).