Mã của bạn cho thấy rằng bạn đang sử dụng kết quả của hoạt động không đồng bộ sau này trong cùng một phương pháp, do đó bạn sẽ phải đối phó với CompletionException
anyway, do đó một cách để đối phó với nó, là
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
}
Tất cả các trường hợp ngoại lệ ném ra bên trong quá trình xử lý không đồng bộ của Supplier
sẽ nhận được gói gọn trong một CompletionException
khi gọi join
, ngoại trừ ServerException
chúng tôi đã gói trong một CompletionException
.
Khi chúng ta lại ném nguyên nhân của CompletionException
, chúng ta có thể gặp phải trường hợp ngoại lệ được kiểm soát, ví dụ: lớp con của Error
hoặc RuntimeException
, hoặc tùy chỉnh của chúng tôi kiểm tra ngoại lệ ServerException
. Mã trên xử lý tất cả chúng với một đa bắt mà sẽ ném lại chúng. Vì kiểu trả về được khai báo là getCause()
là Throwable
, trình biên dịch yêu cầu chúng tôi xử lý loại đó mặc dù chúng tôi đã xử lý tất cả các loại có thể. Các giải pháp thẳng về phía trước là để ném này thực sự không thể ném được bọc trong một AssertionError
.
Ngoài ra, chúng ta có thể sử dụng một tương lai kết quả thay thế cho ngoại lệ tùy chỉnh của chúng tôi:
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
}
Giải pháp này sẽ tái ném tất cả throwables “bất ngờ” ở dạng bọc của họ, nhưng chỉ ném tục ServerException
trong ban đầu của nó biểu mẫu được chuyển qua tương lai exception
. Lưu ý rằng chúng tôi phải đảm bảo rằng a
đã được hoàn tất (như gọi số join()
trước), trước khi chúng tôi truy vấn tương lai exception
, để tránh điều kiện chủng tộc.
điều này là rất tốt đẹp ... – Eugene
câu trả lời rất chi tiết. –