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:
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.
Resource Acquisition Is Initialization (RAII) is a design idea introduced in C++ by Bjarne Stroustrup for exception-safe resource management. Thanks to garbage collection Java doesn't have this feature, but we can implement something similar, using try-with-resources.
The principle that objects own resources is also known as "resource acquisition is initialization," or RAII. When a resource-owning stack object goes out of scope, its destructor is automatically invoked. In this way, garbage collection in C++ is closely related to object lifetime, and is deterministic.
RAII and garbage collection are intended to solve different problems. When you use RAII you leave an object on the stack which sole purpose is to clean up whatever it is you want managed (sockets, memory, files, etc.) on leaving the scope of the method.
RAII avoids using objects in an invalid state. it already makes life easier before we even use the object. There are three error cases to handled: no file can be opened, only one file can be opened, both files can be opened but copying the files failed.
To expand on Radiodef's answer. I think RAII with try-with-resources is totally acceptable pattern for java. But to actually suppress warning
@SuppressWarnings("try")
instead of @SuppressWarnings("unused")
.An example with above points applied:
@SuppressWarnings("try") void myMethod1() { try(MyResource myVar = new MyResource(..)) { //I am not using myVar here } }
Expanding on the pattern itself. I've extensively used it to manage read-write locks and it worked great.
In my code I've used the trick to sometime preemptively unlock some resource to increase concurrency, like this:
try (Guard g1 = new Guard(myLock1)) { someStuffThatRequiresOnlyLock1(); try (Guard g2 = new Guard(myLock2)) { someStuffThatRequiresBothLocks(); if (isSomething) { g1.close(); someMoreSuffThatRequiresOnlyLock2() } else { someMoreSuffThatRequiresBothLocks(); } } }
Locks are always acquired in the same order, but unlocking is performed as needed leaving as much space for concurrent processing as possible. The adjustment to make it work with read-write locks is to modify Guard class to allow repeated closings:
public class Guard implements AutoCloseable { private final Lock lock; private boolean isClosed = false; public Guard(Lock lock) { this.lock = lock; lock.lock(); } @Override public void close() { if (!isClosed) { isClosed = true; lock.unlock(); } } }
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).
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