Search code examples
javaexceptioncode-cleanupfunctional-interface

In Java, can you consolidate identical exception handling logic to one place?


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?


Solution

  • 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.