Votre code suggère que vous utilisez le résultat de la opération asynchrone plus tard dans la même méthode, vous devrez donc faire face à CompletionException
de toute façon, une façon de traiter avec elle, est
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
}
Toutes les exceptions lancées à l'intérieur du traitement asynchrone du Supplier
va s'enveloppées dans un CompletionException
lors de l'appel join
, sauf le ServerException
nous avons déjà enveloppé dans un CompletionException
.
Quand nous sommes-jeter la cause de la CompletionException
, nous pouvons faire face à des exceptions non vérifiées, à savoir les sous-classes de Error
ou RuntimeException
, ou notre coutume vérifié exception ServerException
. Le code ci-dessus gère chacun d'entre eux avec un multi-catch qui les relancera. Puisque le type de retour déclaré de getCause()
est Throwable
, le compilateur exige que nous gérions ce type malgré que nous ayons déjà traité tous les types possibles. La solution directe est de jeter ce jetable réellement impossible enveloppé dans un AssertionError
.
Sinon, nous pourrions utiliser un futur résultat alternatif pour notre exception personnalisée:
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
}
Cette solution re-jeter tous les « inattendus » Throwables sous leur forme enveloppée, mais seulement jeter la coutume ServerException
dans sa version originale formulaire passé via le exception
avenir. Notez que nous devons nous assurer que a
a été complété (comme l'appel join()
d'abord), avant que nous demandions le futur exception
, pour éviter les conditions de course.
c'est tellement agréable ... – Eugene
réponse très détaillée. –