1

I have functions with the same param and response type like;

public ResponseType functionA(ParamType) throws Exception1

public ResponseType functionB(ParamType) throws Exception1

and I call these functions from different places with the same repeating try/catch block. Is there any way to reduce the duplicate code?

try{
    return functionA(obj);
} catch (Exception1 e) { .... }
catch (Exception2 e) { .... }
catch (Exception3 e) { .... }


try{
    return functionB(obj);
} catch (Exception1 e) { .... }
catch (Exception2 e) { .... }
catch (Exception3 e) { .... }

I have tried to create a function like below, but I am getting

Exception e1 is never thrown in try block

as expected.

public ResponseType callFunction(Function<ParamType, ResponseType> function, ParamType obj) {
    try{
        return function.apply(obj)
    }catch (Exception1 e) { .... }
    catch (Exception2 e) { .... }
    catch (Exception3 e) { .... }
}
hellzone
  • 5,393
  • 25
  • 82
  • 148
  • *"Exception e1 is never thrown in try block"* - that means that you're trying to catch a **checked** exception which is not expected to be thrown. So why do you want to catch a checked exception which would never occur to begin with? – Alexander Ivanchenko Oct 19 '22 at 09:33
  • And since method `Function.apply()` as well as all other methods of the functional interfaces doesn't declare checked exceptions, then all other exceptions you're dialing with are runtime exception. And in most cases you should not catch them because they are meant to signify that the code is malfunctioning in some way. – Alexander Ivanchenko Oct 19 '22 at 09:42
  • @AlexanderIvanchenko like you said it is a checked exception, but I need to catch it and do some actions according to it. It is never thrown because I am trying to call my functions with function.apply() method so It is not a good way to create a common wrapper for my functions I think. – hellzone Oct 19 '22 at 09:42
  • 2
    You can define your own functional Interface with the `throws` declaration for the desired exception type: [See this post](https://stackoverflow.com/questions/18198176/java-8-lambda-function-that-throws-exception). – Vinz Oct 19 '22 at 09:45
  • You probably misunderstand, it's impossible to propagate checked exception outside the `java.util.function.Function`. Even if inside a function you're invoking a method that let's say can throw an `IOException` (which is checked), you would need to catch it right on the spot. Otherwise your code would not compile. – Alexander Ivanchenko Oct 19 '22 at 09:46
  • @AlexanderIvanchenko Not to muddy the water, but it's not impossible. Lombok's `@SneakyThrows`, for example – Michael Oct 19 '22 at 09:48
  • @Michael Yep, but we can't annotate a lambda with `@SneakyThrows`. In order to use it, the function has to be implemented as a class. – Alexander Ivanchenko Oct 19 '22 at 09:55
  • In the future, it's much more convenient to provide code in your question that can be compiled, rather than pseudocode. This will increase your chances of getting a timely and high quality answer. – Tim Moore Oct 22 '22 at 02:32

1 Answers1

0

The issue is that Function.apply is not declared to throw any exceptions, so it is not generally possible to throw checked exceptions from an implementation, or to catch a checked exception from it at a call site. (Ignoring unusual workarounds as mentioned in the comments.)

However, Java does not restrict lambda expressions to only be used with standard functional interfaces, so the best approach when you need to handle specific exception types is to create your own.

@FunctionalInterface
interface MyFunction {
    ResponseType apply(ParamType param) throws Exception1, Exception2, Exception3;
}

This can be used in a similar way to java.util.function.Function:

public ResponseType callFunction(MyFunction function, ParamType obj) {
    try{
        return function.apply(obj);
    }
    catch (Exception1 e) { throw new RuntimeException("Exception1"); }
    catch (Exception2 e) { throw new RuntimeException("Exception2"); }
    catch (Exception3 e) { throw new RuntimeException("Exception3"); }
}

(Modified to throw runtime exceptions in the catch blocks so that this will compile)

The calling code is identical to any standard functional interface:

    callFunction(this::functionA, obj);

    callFunction(this::functionB, obj);

or, equivalently:

    callFunction(param -> functionA(param), obj);

    callFunction(param -> functionB(param), obj);
Tim Moore
  • 8,958
  • 2
  • 23
  • 34