Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In java, is there a way to ensure that multiple methods get called in a finally block?

So I have a try/finally block. I need to execute a number of methods in the finally block. However, each one of those methods can throw an exception. Is there a way to ensure that all these methods are called (or attempted) without nested finally blocks?

This is what I do right now, which is pretty ugly :

protected void verifyTable() throws IOException {
    Configuration configuration = HBaseConfiguration.create();
    HTable hTable = null;                                               

    try {
        hTable = new HTable(configuration, segmentMatchTableName);      

        //...
        //various business logic here
        //...

    } finally {                         
        try {
            try {
                if(hTable!=null) {
                    hTable.close(); //This can throw an IOException
                }               
            } finally {
                try {
                    generalTableHelper.deleteTable(configuration, segmentMatchTableName); //This can throw an IOException
                } finally {
                    try {
                        generalTableHelper.deleteTable(configuration, wordMatchTableName); //This can throw an IOException
                    } finally {
                        generalTableHelper.deleteTable(configuration, haplotypeTableName); //This can throw an IOException      
                    }
                }
            }                               
        } finally {
            HConnectionManager.deleteConnection(configuration, true); //This can throw an IOException   
        }
    }               
}

Is there a more-elegant way to do this?

like image 215
sangfroid Avatar asked Oct 07 '22 17:10

sangfroid


1 Answers

The standard (working) way to right resource management in Java (the principle applies to other languages as well) is:

Resource resource = acquire(resource);
try {
    use(resource);
} finally {
    resource.release();
}

Or using the shortcut (with an extra bit of cleverness) in the current version of Java SE:

try (Resource resource = acquire(resource)) {
    use(resource);
}

(As Joe K points out, you may need to wrap the resource to make it confirm to the specific interface that the Java language depends upon.)

Two resources, and you just apply the idiom twice:

Resource resource = acquire(resource);
try {
    SubResource sub = resource.acquire();
    try {
        use(sub);
    } finally {
        sub.release();
    }
} finally {
    resource.release();
}

And in Java SE 7:

try (
    Resource resource = acquire(resource);
    SubResource sub = resource.acquire()
) {
    use(resource, sub);
}

The really great advantage of the new language feature is that resource handling was more often than not broken when written out.

You might have more complicated exception handling. For instance, you don't want to throw low-level exceptions such as IOException through to the application proper - you probably want to wrap in some subtype of RuntimeException. This can, with Java's typicaly verboseness, be factored out using the Execute Around idiom (see this excellent question). From Java SE 8, there will also be shorter syntax with randomly different semantics.

with(new ResourceSubAction() { public void use(Resource resource, SubResource sub) {
    ... use resource, sub ...
}});
like image 79
Tom Hawtin - tackline Avatar answered Oct 10 '22 01:10

Tom Hawtin - tackline