Handling the cause of an ExecutionException

14.4k Views Asked by At

Suppose I have a class defining a big block of work to be done, that can produce several checked Exceptions.

class WorkerClass{
   public Output work(Input input) throws InvalidInputException, MiscalculationException {
      ...
   }
}

Now suppose I have a GUI of some sort that can call this class. I use a SwingWorker to delegate the task.

Final Input input = getInput();
SwingWorker<Output, Void> worker = new SwingWorker<Output, Void>() {
        @Override
        protected Output doInBackground() throws Exception {
            return new WorkerClass().work(input);
        }
};

How can I handle the possible exceptions thrown from the SwingWorker? I want to differentiate between the Exceptions of my worker class (InvalidInputException and MiscalculationException), but the ExecutionException wrapper complicates things. I only want to handle these Exceptions - an OutOfMemoryError should not be caught.

try{
   worker.execute();
   worker.get();
} catch(InterruptedException e){
   //Not relevant
} catch(ExecutionException e){
   try{
      throw e.getCause(); //is a Throwable!
   } catch(InvalidInputException e){
      //error handling 1
   } catch(MiscalculationException e){
      //error handling 2
   }
}
//Problem: Since a Throwable is thrown, the compiler demands a corresponding catch clause.
3

There are 3 best solutions below

2
On BEST ANSWER
catch (ExecutionException e) {
    Throwable ee = e.getCause ();

    if (ee instanceof InvalidInputException)
    {
        //error handling 1
    } else if (ee instanceof MiscalculationException e)
    {
        //error handling 2
    }
    else throw e; // Not ee here
}
3
On

Try/multi-catch:

try {
    worker.execute();
    worker.get();
} catch (InterruptedException e) {
    //Not relevant
} catch (InvalidInputException e) {
    //stuff
} catch (MiscalculationException e) {
    //stuff
}

Or with the ExecutionException wrapper:

catch (ExecutionException e) {
    e = e.getCause();
    if (e.getClass() == InvalidInputException.class) {
        //stuff
    } else if (e.getClass() == MiscalculationException.class) {
        //stuff
    }
}

Or if you want exceptions' subclasses to be treated like their parents:

catch (ExecutionException e) {
    e = e.getCause();
    if (e instanceof InvalidInputException) {
        //stuff
    } else if (e instanceof MiscalculationException) {
        //stuff
    }
}
3
On

You could use an ugly (smart?) hack to convert the throwable into an unchecked exception. The advantage is that the calling code will receive whatever exception was thrown by your worker thread, whether checked or unchecked, but you don't have to change the signature of your method.

try {
    future.get();
} catch (InterruptedException ex) {
} catch (ExecutionException ex) {
    if (ex.getCause() instanceof InvalidInputException) {
        //do your stuff
    } else {
        UncheckedThrower.throwUnchecked(ex.getCause());
    }
}

With UncheckedThrower defined as:

class UncheckedThrower {

    public static <R> R throwUnchecked(Throwable t) {
        return UncheckedThrower.<RuntimeException, R>trhow0(t);
    }

    @SuppressWarnings("unchecked")
    private static <E extends Throwable, R> R trhow0(Throwable t) throws E {
        throw (E) t;
    }
}