Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to best execute a set of methods even if an exception happens

Tags:

java

exception

In a current Java project we have code similar to the following example:

try {
    doSomeThing(anObject);
}
catch (SameException e) {
    // Do nothing or log, but don't abort current method.
}

try {
    doOtherThing(anObject);
}
catch (SameException e) {
    // Do nothing or log, but don't abort current method.
}

// ... some more calls to different method ...

try {
    finallyDoYetSomethingCompletelyDifferent(anObject);
}
catch (SameException e) {
    // Do nothing or log, but don't abort current method.
}

As you can see, several different method are called with the exact same object and for every call the same exception is caught and handled the same (or in a very similar) way. The exception is not re-thrown, but may only be logged and then discarded.

The only reason why there is a try-catch around every single method, is to always execute all of the methods, no matter if a previously executed method failed.

I don't like the above code at all. It takes up a lot of space, is very repetitive (especially the logging done in the catch-block; not presented here) and just looks bad.

I can think of some other ways to write this code, but don't like them very much, either. The following options came to my mind:

Loop-switch sequence / for-case paradigm

(See Wikipedia or The Daily WTF)

for (int i = 0; i <= 9; i++) {
    try {
        switch (i) {
            case 0:
                doSomeThing(anObject); break;
            case 1:
                doOtherSomeThing(anObject); break;
            // ...More cases...
            case 9:
                doYetSomethingCompletelyDifferent(anObject); break;
        }
    }
    catch (SameException e) {
        // Do nothing or log, but don't abort current method.
    }
}

This is obviously bad code, very error-prone and looks amateurish.

Reflection

Use reflection to get Method objects for the methods to call and store them in a list in the order they are supposed to be executed. Then iterate over this list and call the method using anObject as only parameter. The exception is handled inside of the loop.

I don't like this approach, as bugs (for example typos in the method names) only pop up during runtime and the Reflection API is somewhat chatty.

Functor

Create a Functor class like this:

private class Functor
{
    void doStuff(MyObject object) throws SameException;
}

Then create a list of Functor objects that call the methods. Like this:

List<Functor> functors = new ArrayList<Functor>();

functors.add(new Functor() {
    @Override
    public void execute(MyObject anObject) {
        doSomeThing(anObject);
    }
});

functors.add(new Functor() {
    @Override
    public void execute(MyObject anObject) {
        doOtherSomeThing(anObject);
    }
});

Later, iterate this list and call execute() on every Functor object. I can summarize my feeling about this approach with two words: Code bloat.


As I don't really like all four approaches, I would like to discuss this problem here. What do you feel is the best approach? How did you solve similar problems in the past? Is there maybe a much simpler solution I missed completely?

like image 253
Tobias Müller Avatar asked Mar 24 '09 21:03

Tobias Müller


People also ask

How do you continue a program execution even after throwing an exception?

Resuming the program When a checked/compile time exception occurs you can resume the program by handling it using try-catch blocks. Using these you can display your own message or display the exception message after execution of the complete program.

What are the two main ways to deal with exceptions in a method?

You can either use the try-catch-finally approach to handle all kinds of exceptions. Or you can use the try-with-resource approach which allows an easier cleanup process for resources.

Does throwing an exception end the method?

When an exception is thrown the method stops execution right after the "throw" statement. Any statements following the "throw" statement are not executed.


2 Answers

I would advocate the refactoring approach (or "Why did we get here in the first place?"):

Consider why the individual methods can throw the exception after doing "stuff" with myObject and that exception can then be safely ignored. Since the exception escapes the method, myObject must be in an unknown state.

If it's safe to ignore the exception, surely it must be the wrong way to communicate that something went wrong in each method.

Instead, maybe it's each method that needs to do some logging on failure. If you don't use static loggers, you can pass a logger to each method.

like image 151
PeterR Avatar answered Nov 09 '22 03:11

PeterR


The functor approach is the nicest one to my mind - it's just a shame that Java doesn't have a nicer way of representing closures or delegates. That's basically what you're really after, and in C# (and many other languages) it would be trivial.

You can cut down on the physical bloat somewhat by using something like:

Functor[] functors = new Functor[] {
    new Functor() { @Override public void execute(MyObject anObject) {
        doSomeThing(anObject);
    }},
    new Functor() { @Override public void execute(MyObject anObject) {
        doSomeOtherThing(anObject);
    }}
};

The whitespace collapsing here may well be against the style guide you're using, but I think it makes the code easier to actually read, in that you can see the meat more easily.

Better start lobbying for closures in Java 8 ;)

like image 23
Jon Skeet Avatar answered Nov 09 '22 01:11

Jon Skeet