Ihr Code schlägt vor, dass Sie das Ergebnis des verwenden später asynchroner Betrieb in der gleichen Methode, so dass Sie auf jeden Fall mit CompletionException
zu tun haben werden, so eine Art und Weise, damit umzugehen, sind
public void myFunc() throws ServerException {
// Some code
CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> {
try { return someObj.someFunc(); }
catch(ServerException ex) { throw new CompletionException(ex); }
});
// Some code running in parallel to someFunc()
A resultOfA;
try {
resultOfA = a.join();
}
catch(CompletionException ex) {
try {
throw ex.getCause();
}
catch(Error|RuntimeException|ServerException possible) {
throw possible;
}
catch(Throwable impossible) {
throw new AssertionError(impossible);
}
}
// some code using resultOfA
}
Alle Ausnahmen innerhalb der asynchronen Verarbeitung der Supplier
geworfen wird in eine bekommen gewickelten CompletionException
beim Aufruf join
, außer der ServerException
haben wir bereits in eine CompletionException
gewickelt.
Wenn wir wieder wirft die Ursache der CompletionException
, können wir nicht markiert Ausnahmen, das heißt Subklassen von Error
oder RuntimeException
oder unseren eigenen geprüfte Ausnahme ServerException
Gesicht. Der obige Code behandelt alle von ihnen mit einem Mehrfach-Fang, der sie erneut werfen wird. Da der deklarierte Rückgabetyp getCause()
Throwable
ist, verlangt der Compiler, dass wir diesen Typ behandeln, obwohl wir bereits alle möglichen Typen behandelt haben. Die unkomplizierte Lösung ist es, diese eigentlich unmöglich werfen in eine AssertionError
gewickelt werfen.
Alternativ könnten wir ein alternatives Ergebnis Zukunft für unsere benutzerdefinierte Ausnahme verwenden:
public void myFunc() throws ServerException {
// Some code
CompletableFuture<ServerException> exception = new CompletableFuture<>();
CompletableFuture<A> a = CompletableFuture.supplyAsync(() -> {
try { return someObj.someFunc(); }
catch(ServerException ex) {
exception.complete(ex);
throw new CompletionException(ex);
}
});
// Some code running in parallel to someFunc()
A resultOfA;
try {
resultOfA = a.join();
}
catch(CompletionException ex) {
if(exception.isDone()) throw exception.join();
throw ex;
}
// some code using resultOfA
}
Diese Lösung wird alle „unerwartet“ Throwables in ihre eingewickelt Form wieder werfen, sondern nur die benutzerdefinierte ServerException
in seiner ursprünglichen werfen Formular über die exception
Zukunft übergeben. Beachten Sie, dass wir sicherstellen müssen, dass a
abgeschlossen wurde (wie zum Beispiel join()
zuerst), bevor wir die exception
Zukunft abfragen, um Race-Bedingungen zu vermeiden.
das ist so schön ... – Eugene
sehr detaillierte Antwort. –