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



Question:

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?


Solution:1

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.


Solution:2

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


Solution:3

On the first look, I agree with PeterR: if it is safe to ignore the exception that easily, maybe that method should not be throwing an exception at all.

However, if you're sure that's exactly what you want, say, perhaps you're working with methods from a 3rd party library which insist on throwing specific exceptions, I would opt for the following approach:

  1. create an interface containing all the methods that can be called:

            public interface XyzOperations {       public void doSomething(Object anObject);       public void doOtherThing(Object anObject);       ...       public void finallyDoYetSomethingCompletelyDifferent(Object anObject);  
  2. create a default implementation class for those methods appropriate methods, possibly refactoring them from some other place:

          public class DefaultXyzOperations implements XyzOperations {      ...       }  
  3. use a Java Proxy class to create a dynamic proxy on XyzOperations which would delegate all methods to DefaultXyzOperations, but, would have centralized exception handling in its InvocationHandler. I didn't compile the following, but it's a basic outline:

        XyzOperations xyz = (XyzOperations)Proxy.newProxyInstance(          XyzOperations.class.getClassLoader(),          new Class[] { XyzOperations.class },          new InvocationHandler() {              public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                   try {                        method.invoke(new DefaultXyzOperations(), args);                   }                   catch(SameException e) {                       // desired exception handling                   }              }          });  
  4. use that proxy instance from then on, simply calling the desired methods

Alternatively, you could use AspectJ or similar AOP solution to add around advice to all methods of XyzOperations and do the exception handling there.

Whether you would rather introduce a new dependency, or write proxies manually is up to your personal preference and the total amount of code where you need such behavior.


Solution:4

I agree with PeterR. I find it hard to believe that you really want to continue execution of something after an exception has been thrown. If you do, then something exceptional probably has not actually happened.

Put another way, exceptions should not be used for logging or flow control. They should only be used when something exceptional has happened that the code at the level where the exception was thrown cannot deal with.

As such, I would internalize the logging messages and remove the exceptions that are being thrown.

At a minimum, I think you need to go back and re-understand what the code is trying to do and what business value or rules are being implemented. As PeterR said, try to understand "why did we get here in the first place?" part of the code and what exactly the exceptions mean.


Solution:5

Are the methods you're calling under your control? If so, in this special case returning error codes (or objects) might yield to a better overall design than using exceptions:

handle(doSomething(anObject));  handle(doOtherThing(anObject));  // some more calls to different methods  handle(finallyDoYetSomethingCompletelyDifferent(anObject));  

with

private void handle(ErrorCode errorCode) {    // Do something about it  }  

and

private ErrorCode doSomething(Object anObject) {    // return ErrorCode describing the operation's outcome  }  

This seems less verbose, although not DRY.

Alternatively, you use some AOP mechanism to intercept the calls to doSomething, doOtherThing and finallyDoYetSomethingCompletelyDifferent with an Around Advice that first handles and then discards the Exception. Combine that with RuntimeExceptions and a pointcut based on some nice descriptive annotation and you perfectly capture what seems to be some kind of hidden crosscutting concern.

I do confess that I like the Functor approach, tho.

EDIT: Just saw your comment on one of the answers. I would probably go with the AOP approach in that case.


Solution:6

Leaving aside the refactoring issue, AspectJ (or similar) seems the easiest way to transparently catch/report these exceptions. You should be able to configure such that it'll weave the try/catch around the method calls even if you add new ones (the code block above would, I suspect, be quite fragile in the face of someone modifying that code without fully understanding the rationale behind it)


Solution:7

If you are going the different code style route, I would stick with a simple:

try { doSomeThing(anObject); } catch (SameException e) { Log(e); }  try { doOtherThing(anObject); } catch (SameException e) { Log(e); }  // ... some more calls to different method ...  

Update: I don't see how going with a syntax like the Functor's approach reduces any of the code involved. As mentioned by Jon, java doesn't support a simple syntax to reduce it further. If it were c# there are plenty of variations you can do, all around the fact that there isn't much extra syntax to compose methods like that i.e. an expression like actions.Add(() => doSomething(anObject));


Solution:8

Let me elaborate on the functor approach a bit more...

Depending on the complexity of your app, sometimes it is worth to move part of your business logic to a conf file, where it can be expressed more appropriately and briefly. This way you separate the technical details (the functor creation/invocation, exception handling) from the business logic - the definition of which methods and in what order are to be called.

In the simplest form it could be something like this:

mypackage.Action1  mypackage.Action2  ...  

where ActionX is a class implementing the Functor class (or interface).


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »