views:

124

answers:

3

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;
+2  A: 

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).

tzaman
Thanks... I guest I could also use a template method pattern, which requires ugly class hierarchy. Cheers.
drozzy
+2  A: 

As tzaman said, the secret is using finally; generally:

Resource r = allocateResource();
try {
    // use resource
}
finally {
    r.dispose();
}

Things to note here:

  • try and finally each create a variable scope. So allocating your resource within the try clause won't work, as it won't be visible in the finally clause- you've got to declare the resource's variable before the try statement.

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:

  • Java's syntax for anonymous classes is excessively verbose
  • Checked exceptions within doStuff complicate things too much

, two points which I hope will be solved in Java 7.

You can find this kind of code throughout Spring, for instance:

alex
Thanks, the functor thing looks interesting. To bad there is no sugar to simplify it.
drozzy
Also - don't you mean close() instead of dispose()? Java has a Closeable interface.
drozzy
"dispose" just sounded more generic :-p. It's just pseudocode :-p
alex
+1  A: 

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 )

OscarRyz
What do the underscores everywhere mean? Temporary variable names?
drozzy
That's not Java ( the language ) but I generic class wrapper I created. You may think of it as a *poor pass by reference* substitute. It is defined as: `class _<E>{ public E _; }` :P
OscarRyz
Sorry, I am still not sure what underscores are. You are saying they are not part of java language???
drozzy
@drozzy: No in the sense `int` or `for` are. The underscore is just another class name and another field name. I just use it because it makes the code look cleaner. Here's for comparison: With a regular name: http://pastebin.com/RQPTTNpK Using uderscore: http://pastebin.com/Tzur8b5c diff: http://pastebin.com/cjhr1gwe
OscarRyz