BadPractice18 - SpotBugsExtensionForSpringFrameWork/CS5098 GitHub Wiki
Bad Practice - Should use AsyncResult<V>
return type to handle @Async exception instead of Future<V>
return type
For those methods with return type void, we should avoid using try-catch block because the process that try to catch exception has already disconnected with the invocation method.
For those methods with return value, developers used to use Future<V>
as the return type. Future<V>
is the interface that Java standard library provided to represent the result of an asunchronous computation. However, it's not a good practice to use Future<V>
to handle @Async
exception, developers should treat AsyncResult<V>
as a good practice.
@Async
public Future<Integer> asyncMethodWithReturnType() {
System.out.println("Execute method asynchronously - "
+ Thread.currentThread().getName());
int a = 1;
int b = 0;
int c = 0;
c = a/b;
return new Future<Integer>(c);
}
public void testAsyncAnnotationForMethodsWithReturnType() {
System.out.println("Invoking an asynchronous method. "
+ Thread.currentThread().getName());
try {
Future<String> future = asyncAnnotationExample.asyncMethodWithReturnType();
} catch (ArithmeticException e) {
logger.error("Handling exception", e);
}
}
When the return type of the asynchonous method is Future<V>
, the exception thrown during the execution can be accessed by the caller. That's because there is a method Future.get()
that throws ExecutionException
which means developers can use the get()
method to obtain any exception thrown during the execution.
public interface Future<V> {
...
V get() throws InterruptedException, ExecutionException;
...
}
Although Future<V>
has the ability to catch exception, Spring provides a way to handle exception of invoked method. AsyncResult<V>
is a Spring provided class implements interface ListenableFuture<V>
which can track the result of asynchronous method execution. Also, since Spring 4.2, it provides a method to retrieve thrown exception during the execution of the asynchonous method.
public class AsyncResult<V> implements ListenableFuture<V> {
...
@Override
@Nullable
public V get() throws ExecutionException {
if (this.executionException != null) {
throw (this.executionException instanceof ExecutionException ?
(ExecutionException) this.executionException :
new ExecutionException(this.executionException));
}
return this.value;
}
...
}
First, we can simply change the Future<V>
return type to AsyncResult<V>
. Second, we just need to call the future.get()
method to let the main process to handle the thrown exception.
@Service
public class AsyncService {
@Async
public AsyncResult<Integer> asyncMethodWithResult() {
int a = 1;
int b = 0;
int c = 0;
c = a/b;
return new Future<Integer>(c);
}
}
public class Test {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
AsyncService asyncService;
public void test() {
try {
Future future = asyncService.asyncMethodWithResult();
future.get();
} catch (ArithmeticException e) {
logger.error("exception occurs", e);
}
}
}
https://www.programmersought.com/article/34932801814/
Supporting Exception Handling for Futures in Java