Is there something like Python with context manager in Java?
For example say I want to do something like the following:
getItem(itemID){
Connection c = C.getConnection();
c.open();
try{
Item i = c.query(itemID);
}catch(ALLBunchOfErrors){
c.close();
}
c.close();
return c;
}
where in python I just have:
with( C.getConnection().open() as c):
Item i = c.query(itemID);
return i;
Java 7 has introduced a new feature to address this issue: "try with resources"
http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
Close resource quietly using try-with-resources
The syntax is to place the resource in parentheses after the try keyword:
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
Prior to Java 7, you can use a finally block.
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
} finally {
if (br != null) br.close();
}
There's an alternative using a generic wrapper like this:
final _<Item> item = new _<Item>();
final _<Connection> c = new _<Connection>();
with( factory, c, new Runnable() {
public void run(){
item._ = c._.query( itemId );
}
});
return item._;
NOTE: The Java way is the one you've just described. This other is just for "fun" and experimentation:
The _
is a generic wrapper and the with
function is an utility class defined somewhere else as:
class WithUtil {
public static void with( ConnectionFactory factory,
_<Connection> c, Runnable block ) {
try {
c._ = factory.getConnection();
c._.open();
block.run();
} catch( Exception ioe ){
}finally{
if( c._ != null ) try {
c._.close();
} catch( IOException ioe ){}
}
}
}
In strict theory, you could re-use it to perform other stuff, like deleting an item:
public void deleteItem( final int itemId ) {
final _<Connection> c = new _<Connection>();
with( factory, c, new Runnable() {
public void run(){
Item item = c._.query( itemId );
if( ! item.hasChildren() ) {
c._.delete( item );
}
}
});
}
or update it
public void update( final int itemId, String newName ) {
final _<Connection> c = new _<Connection>();
with( factory, c, new Runnable() {
public void run(){
Item item = c._.query( itemId );
item.setName( newName );
c._.update( item );
}
});
}
Without having to integrate the try/catch again.
Here's a full working demo that proofs the concept ( and doesn't do anything else )
Not at the moment; Java still hasn't added syntactic sugar for this pattern. Still, it won't get as clean as with
(Python) or using
(C#), but you can at least clean that up a little bit by just having one call to c.close()
inside a finally
block, instead of twice as you've done:
try {
// use c
} finally {
c.close()
}
This also brings it in line with how both with
and using
are actually implemented, which is a try..finally
block (not a try..catch
).
As tzaman said, the secret is using finally; generally:
Resource r = allocateResource();
try {
// use resource
}
finally {
r.dispose();
}
Things to note here:
If you have several resources to allocate, the general pattern applies cleanly, but this is often not evident to beginners:
Resource1 r1 = allocateResource1();
try {
// code using r1, but which does not need r2
Resource r2 = allocateResource2();
try {
// code using r1 and r2
}
finally {
r2.dispose();
}
}
finally {
r1.dispose();
}
, and so on and so forth if you have more resources to allocate. If you have a couple of them, you will surely be tempted to try and avoid deep nesting of try... finally statements. Don't. You can get resource deallocation and exception handling right without nesting so many try... finally statements, but getting it right without nesting try... finally is even uglier than deep nesting.
If you frequently need to use a set of resources, you can implement a functor-based method to avoid the repetition, something like:
interface WithResources {
public void doStuff(Resource1 r1, Resource2 r2);
}
public static void doWithResources(WithResources withResources) {
Resource r1 = allocateResource1();
try {
Resource r2 = allocateResource2();
try {
withResources.doStuff(r1, r2);
}
finally {
r2.dispose();
}
}
finally {
r1.dispose();
}
}
Which then you can use like this:
doWithResources(new WithResources() {
public void doStuff(Resource1 r1, Resource2 r2) {
// code goes here
}
});
doWithResources will automatically handle allocation and deallocation correctly, and your code will have less repetition (which is a good thing). However:
, two points which I hope will be solved in Java 7.
You can find this kind of code throughout Spring, for instance:
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