Sorry for the TL;DR, but I feel like it needs some explanation or it will be misunderstood.
I have a method that makes a call to (generally external) code which I expect to sometimes throw a RuntimeException, and uses futures which can throw InterruptedException or ExecutionException, and I want to be able to return an ordered set of returned values to from the call up until the exception was thrown, and the exception that was thrown. I wrote something that works, but unfortunately, the way the code looks makes me feel like I'm doing something wrong. What I think I really want is multi-catch to be a more generic concept that. That would allow pretty clean code to solve it, kind of like this:
public class SomeResults {
private final Set<SomeReturnType> valuesReturned;
private final @Nullable RuntimeException | ExecutionException | InterruptedException exception;
public SomeResults(Set<SomeReturnType> valuesReturned, RuntimeException | ExecutionException exception {
this.valuesReturned = valuesReturned;
this.exception = exception;
}
public Set<SomeReturnType> getValuesReturned() {
return valuesReturned;
}
public @Nullable RuntimeException | ExecutionException | InterruptedException getException();
}
And have a method that wraps up making the calls to the external code ...
generateResults(Bar bar) {
// Setup code
Set<SomeReturnType> valuesReturned = new LinkedHashSet<>();
...
// loop
{
// stuff
... // exceptions in this method should throw except for this one external code call
try {
valuesReturned.add(externalCodeCallGetSomeReturnValue(bar))
}
catch( RuntimeException | ExecutionException | InterruptedException e) {
return new MyResults(valuesReturned, e)
}
...
}
return new MyResults(valuesReturned, (RuntimeException | ExecutionException | InterruptedException) null);
}
And subsequently do
SomeResults myResults = foo.generateResults(new Bar());
if(myResults.getException() != null) {
throw(myResults.getException);
}
Etc. Note that I do note always want to immediately rethrow the exception - it depends on who is using these results what they will want to do with them. I might do something like
try {
SomeResults myResults = foo.generateResults(new Bar());
Foobar Foobar = new Foobar(myResults);
}
catch(Exception e) {
// I don't want to see any exceptions from externalCodeCallGetSomeReturnValue(bar) here
...
}
Of course, I could let the exception get thrown in the function that generates results, instead of catching the exception and returning it as a result. This has two pretty big issues: 1. Now returning the set of values is going to be awkward - I could perhaps pass in a Set to the method that needs to "return" results and it modifies that set instead of returning a set. That allows the set to be up to date when the exception is returned. Eg
generateResults(Bar bar, Set<SomeReturnType> orderedListForMeToWrite) throws ExecutionException, InterruptedException
- What if code surrounding the external method call throws a runtime exception? Now I have no easy way of distinguishing if the exception call was from the actual call to the external code, or something else! I actually ran into this issue when attempting this design. The code threw IllegalArgumentException from somewhere else, and my code handling treated it as if it had been thrown from SomeReturnType externalCodeCallGetSomeReturnValue(Bar bar). This seemed like a code health issue, which is why I moved away from this solution.
The solution I went with is to just store the exception as an Exception. However, I hated losing that type information. With no additional code work, if something wanted to throw it, it will have to declare "throws Exception", which is not good, similar code health issues there. Is there a good way to handle this situation? What I ended up doing to get it to work the way I wanted it to is as follows:
public static class SomeResults {
private final Set<SomeReturnType> orderedReturnValues;
private final @Nullable Exception exception;
AsyncEchoesResult(Set<SomeReturnType> responses) {
this.orderedResponses = responses;
this.exception = null;
}
AsyncEchoesResult(Set<SomeReturnType> responses, RuntimeException exception) {
this.orderedResponses = responses;
this.exception = exception;
}
AsyncEchoesResult(Set<SomeReturnType> responses, ExecutionException exception) {
this.orderedResponses = responses;
this.exception = exception;
}
AsyncEchoesResult(Set<SomeReturnType> responses, InterruptedException exception) {
this.orderedResponses = responses;
this.exception = exception;
}
public Set<SomeReturnType> getResponses() {
return orderedResponses;
}
public @Nullable Exception getException() {
return exception;
}
public void throwExceptionIfExists() throws ExecutionException, InterruptedException {
try {
throw (exception);
}
catch (RuntimeException | ExecutionException | InterruptedException e) {
throw e;
}
catch (Exception e) {
throw new RuntimeException("Unexpected exception type in SomeResults",e);
}
}
}
Obviously, this is pretty ugly. If I hate the constructors as they are I can easily enough replace them with a single one that takes an Exception, but that weakening the type-checking to only the runtime call of throwException(). Anyway, are there alternatives that work better? Note that I'm using with JDK 7 so while JDK 8 answers would be interesting, that won't fix it for what I'm working on.