views:

375

answers:

2

I cooked up a class ExceptionHandler<T extends Exception, OptionalReturnType> (see below) to eliminate some (what I view as) boilerplate code which was cluttering up actual implementation, while still providing a hook for explicit Exception handling if desired in the future. For the most part, in my application (essential a scientific computation), there is no such thing as recovery from exceptions - I need a log of the problem so I can fix it, but otherwise I'm just going to re-run once the problem is corrected.

Do other people do this (at least, in my specific application situation)? Is it dumb to do so (if yes, some explanation as to why would be nice)?

ExceptionHandler:

public abstract class ExceptionHandler<ExceptionType extends Exception,OptionalReturn> {
 public abstract OptionalReturn handle(ExceptionType e);

//assorted boilerplate ExceptionHandling, e.g.:

 public static <ET extends Exception> ExceptionHandler<ET, ?> swallower(final boolean printStackTrace, final String string) {
  return new ExceptionHandler<ET,Object>() {
   @Override public Object handle(ET e) {
    if(printStackTrace) { e.printStackTrace(); }
    if(string!=null && !string.isEmpty()) { System.err.println(string); }
    return null;
   }
  };
 }

 public static <ET extends Exception> ExceptionHandler<ET, ?> swallower() { return swallower(false,null); }

}

example use (which I'm in the process of chopping down so I'm actually not writing quite so much):

public class Getter<From> implements Function<Future<? extends From>, From> {

private ExceptionHandler<InterruptedException,?> IEH;
private ExceptionHandler<ExecutionException,?> EEH;

public static final ExceptionHandler<InterruptedException,?> IEH_SWALLOWER = ExceptionHandler.swallower(true,"Returning null.");
public static final ExceptionHandler<ExecutionException,?> EEH_SWALLOWER = ExceptionHandler.swallower(true,"Returning null.");

private Getter() { this(IEH_SWALLOWER,EEH_SWALLOWER); }
private Getter(ExceptionHandler<InterruptedException,?> IEH, ExceptionHandler<ExecutionException,?> EEH) {
    this.IEH = IEH;
    this.EEH = EEH;
}

public static <T> Getter<T> make() { return new Getter<T>(); }

public static <T> Getter<T> make(ExceptionHandler<InterruptedException,?> IEH, ExceptionHandler<ExecutionException,?> EEH) {
    return new Getter<T>(IEH, EEH);
}

@Override public From apply(Future<? extends From> from) {
    if (from==null) throw new NullPointerException("Null argument in call with Getter.");
    return getter(from, IEH, EEH);
}

private static <T> T getter(Future<T> src, ExceptionHandler<InterruptedException,?> IEH, ExceptionHandler<ExecutionException,?> EEH) {
    try { return src.get(); }
    catch (InterruptedException e) { IEH.handle(e); }
    catch (ExecutionException e) { EEH.handle(e); }
    return null;
    }

}

which is used with the Guava libraries to do some embarrassingly-parallel calculations, and makes the actual Iterable transformation of Futures into something like Iterables.transform(futureCollection,Getter.make()) instead of tangle of inner-classes and exception handling.

+1  A: 

I find the code honestly hard to follow and understand. It's full of static which is usually a bad sign in OO design and it's hard to follow with the generics.

Wouldn't something simpler like this work as well?

private static <T> T getter(Future<T> src) {
    try { return src.get(); }
     catch (InterruptedException e) { handle( "some text"); }
     catch (ExecutionException e) { handle( e ) }
     return null;
    }

You can implement as many handle method as necessary in a base class (or in a static utility class) and use them in the catch block as necessary. Methods will be selected based on the signature, so if you want to print the text, you pass the string, if you want the stack trace you pass the exception (or both). Which leads to the combinations:

handle( String msg )
handle( Exception e )
handle( Exception e, String msg )

This solution has less if, which is usually a good sign as well.

But I have maybe missed a point, given that the code you published is just an excerpt of the whole code.

Have a look otherwise at this question, which is also related: http://stackoverflow.com/questions/2236063/pluggable-error-handling-strategy/2236437#2236437

EDIT

If the solution I proposed above is too simple for your need, here are two other ways:

public class AbstractGetter<From> implements Function<Future<? extends From>, From> {

private abstract handleInterrupt( Exception e );
private abstract handleExecution( Exception e );

private static <T> T getter(Future<T> src ) {
    try { return src.get(); }
    catch (InterruptedException e) { handleInterrupt(e) }
    catch (ExecutionException e) { handleExecution(e) }
    return null;
    }
}

And you implement the X concrete class that correspond the various exception handling strategies. That's essentially the template pattern.

You can still use delegation, but at a more coarse-grained level. Instead of providing individual handler, you provide a handler strategy. That's kind of variation of the strategy pattern then.

  public interface ErrorStrategy
  {
        public void handleInterrupt(Exception e);
        public void handleExecution(Exception e);
  }

  public class Getter<From> implements Function<Future<? extends From>, From> {

  ErrorStrategy handler = new DefaultErrorStrategy(). // default one

  public Getter<From>()
  {
  }

  public Getter<From>( ErrorStrategy h )
  {
      this.handler = h.
  }

  private static <T> T getter(Future<T> src ) {
    try { return src.get(); }
    catch (InterruptedException e) { handler.handleInterrupt(e) }
    catch (ExecutionException e) { handler.handleExecution(e) }
    return null;
    }
 }

You can create the X error handling strategies that you need.

ewernli
ah, the statics are mostly sugar to avoid the huge constructor calls with a generic argument (e.g., Getter<List<Set<Foo>>> bar = new Getter<List<Set<Foo>>>() vs. Getter<List<Set<Foo>>> bar = Getter.make() ).the private method is static mostly as a reminder that all Getter's do the same thing, so they can use one method, but some delegation is required to wrangle generics/inheritance.
Carl
Yes. I was more speaking about the generics related to exception handling only.
ewernli
re:edit: that seems very similar to what I'm doing currently - ExceptionHandler is a strategy for handling a specific type of Exception. In my example case, the default strategies are specified in the base class, with the option to provide specific strategies when constructing that class.
Carl
Sure, it's a question to find the right balance. I just think that your code is too complicated to grasp and that it can be simplified a bit (I still don't get the necessity of the 2nd generic param in `ExceptionHandler` and I was really confused with all the `static` especially `this.IEE` and `this.EEH` that are in capital letters but are *not* static and have an obscure name at first sight). You've posted the code for feedback, I've suggested 3 alternative which are simpler in my opinion -- then it's up to you.
ewernli
+1  A: 

I think it's a good solution, but it could benefit from an ExceptionHandlerFactory and some xml files.

GreenieMeanie
I dare to disagree. Adding more stuff is rarely a solution -- especially XML files that needs to be parsed, etc. The art is to make things *simple*, not *complex*.
ewernli
...in myth, what (1) color and (2) disposition do trolls usually present?
Carl
though, yes, I did consider the "why bother" solution. The audience for the code, however, is scientists, not developers. The exception handling in place is a distraction for 95% of them, but the 5% interested in alternative handling shouldn't find my implementation too onerous. At least, that's the plan.
Carl
Brown and hungry?
GreenieMeanie