2

I'm trying to clean up some Java code. There are many static factory methods that all do the same exception handling. As an example, consider createA:

public static A createA() throws XXXX, YYYY {
    try {
        return somethingThatThrows();
    } catch (InterruptedException | ExecutionException e) {
        Throwable throwable = e.getCause();
        if (throwable instanceOf XXXX) {
            throw (XXXX) throwable;
        } else if (e instance of YYYY) {
            throw (YYYY) throwable;
        } else if (throwable != null) {
            throw new RuntimeException(throwable);
        } else {
            throw new RuntimeException(e);
        }
    }
}         

There are many of these create methods (each of which returns a different type). For each of these methods, a copy of this exception handling exists (i.e. it's duplicated). I'm hoping there is a way to avoid all of this identical code and only have this logic in one place.

Of course, without exception handling, you simply extract the logic to a helper function and the duplication is solved - the fact that this has exception handling makes it different. The following code does not build:

public static void helper(final Exception e) {
    Throwable throwable = e.getCause();
        if (throwable instanceOf XXXX) {
            throw (XXXX) throwable;
        } else if (e instance of YYYY) {
            throw (YYYY) throwable;
        } else if (throwable != null) {
            throw new RuntimeException(throwable);
        } else {
            throw new RuntimeException(e);
        }
}  

public static A createA() throws XXXX, YYYY {
    try {
        return somethingThatThrows();
    } catch (InterruptedException | ExecutionException e) {
        handle(e);
    }
}         

Does anyone have any suggestions?

sabee
  • 217
  • 1
  • 11

2 Answers2

3

This can be handled in a functional way as below:

@FunctionalInterface
interface SomethingThatThrows<T> {
    T execute() throws XXXX, YYYY, InterruptedException,ExecutionException;
}

private static <T> T handledFuntion(SomethingThatThrows<T> function) throws XXXX, YYYY {
    try {
        return function.execute();
    } catch (InterruptedException | ExecutionException e) {
        Throwable throwable = e.getCause();
        if (throwable instanceof XXXX) {
            throw (XXXX) throwable;
        } else if (e instanceof YYYY) {
            throw (YYYY) throwable;
        } else if (throwable != null) {
            throw new RuntimeException(throwable);
        } else {
            throw new RuntimeException(e);
        }
    }
}

// Use lambda literal - may be better when arguments are involved
public A createA(String arg1) throws XXXX, YYYY {
   return handledFuntion(() -> {
         // write code just like you'd write it in try{} body - 
         // all arguments to createA() are available
         return new A(arg1);
     });
}

// use a method handle, works best when there are no arguments
public B createB() throws XXXX, YYYY {
       return handledFuntion(this::somethingThatMakesB);
}


private B somethingOtherThatMakesB() throws XXXX, YYYY, InterruptedException,ExecutionException {
    // Some logic that creates and returns B
}

Edit: Incorporated @Arkadiy's answer.

Loganathan
  • 903
  • 2
  • 10
  • 23
  • Thanks! Is there a way to do this if the create methods have different types of parameters? – sabee Jan 30 '18 at 20:12
  • Also, these are static factory methods! Can `handledFunction` be called from a static factory method? – sabee Jan 30 '18 at 20:15
  • @sabee Method references are a convenient form which can always be replaced by lambda expressions, with which we can call any method or run any statement. One thing to make sure when using a lambda expression is that the expression should have the code that may not throw any exception or will throw only the exception as in the functional interface and should not throw any extra checked exception. If it is desired to have more exceptions thrown make the functional interface accordingly. And the utility method can be made as static as well. – Loganathan Jan 31 '18 at 01:49
-1

Try to extract the common logic into a private method and call it:

public static A createA() throws XXXX, YYYY {
    try {
        return somethingThatThrows();
    } catch (InterruptedException | ExecutionException e) {
       processInterruptedExcutionExceptions(e);
    }
    return null;
}

private static void processInterruptedExcutionExceptions(final Exception e) throws XXXX, YYYY {
        Throwable throwable = e.getCause();
        if (throwable instanceOf XXXX) {
            throw (XXXX) throwable;
        } else if (e instance of YYYY) {
            throw (YYYY) throwable;
        } else if (throwable != null) {
            throw new RuntimeException(throwable);
        } else {
            throw new RuntimeException(e);
        }
}
Dmytro Maslenko
  • 2,247
  • 9
  • 16