Try-catch是用来帮助异常处理的。这意味着它将在某种程度上帮助我们的系统变得更加健壮:尝试从意外事件中恢复。
我们怀疑在执行和指令(发送消息)时可能会发生一些事情,因此它被包含在try中。如果发生了几乎意想不到的事情,我们可以做些什么:我们编写捕获。我不认为我们调用只是为了记录异常。我认为catch块是为了给我们从错误中恢复的机会。
现在,假设我们从错误中恢复,因为我们可以修复错误。如果能再试一次,那就太好了:
try{ some_instruction(); }
catch (NearlyUnexpectedException e){
fix_the_problem();
retry;
}
这将很快陷入永恒循环,但让我们假设fix_the_problem返回true,然后重试。假设在Java中没有这样的东西,你将如何解决这个问题?你认为解决这个问题的最佳设计代码是什么?
这就像一个哲学问题,因为我已经知道Java不直接支持我所要求的内容。
使用带有本地状态标志的while循环。初始化标志为false,并在操作成功时将其设置为true,如下所示:
boolean success = false;
while(!success){
try{
some_instruction();
success = true;
} catch (NearlyUnexpectedException e){
fix_the_problem();
}
}
这将不断重试,直到成功。
如果你只想重试一定次数,那么也可以使用计数器:
boolean success = false;
int count = 0, MAX_TRIES = 10;
while(!success && count++ < MAX_TRIES){
try{
some_instruction();
success = true;
} catch (NearlyUnexpectedException e){
fix_the_problem();
}
}
if(!success){
//It wasn't successful after 10 retries
}
这将尝试最多10次,如果不成功,直到那时将退出,如果它成功之前。
强制性的“企业级”解决方案:
public abstract class Operation {
abstract public void doIt();
public void handleException(Exception cause) {
//default impl: do nothing, log the exception, etc.
}
}
public class OperationHelper {
public static void doWithRetry(int maxAttempts, Operation operation) {
for (int count = 0; count < maxAttempts; count++) {
try {
operation.doIt();
count = maxAttempts; //don't retry
} catch (Exception e) {
operation.handleException(e);
}
}
}
}
并呼吁:
OperationHelper.doWithRetry(5, new Operation() {
@Override public void doIt() {
//do some stuff
}
@Override public void handleException(Exception cause) {
//recover from the Exception
}
});
这里是我的解决方案类似于其他人可以包装一个函数,但允许您获得函数返回值,如果它成功。
/**
* Wraps a function with retry logic allowing exceptions to be caught and retires made.
*
* @param function the function to retry
* @param maxRetries maximum number of retires before failing
* @param delay time to wait between each retry
* @param allowedExceptionTypes exception types where if caught a retry will be performed
* @param <V> return type of the function
* @return the value returned by the function if successful
* @throws Exception Either an unexpected exception from the function or a {@link RuntimeException} if maxRetries is exceeded
*/
@SafeVarargs
public static <V> V runWithRetriesAndDelay(Callable<V> function, int maxRetries, Duration delay, Class<? extends Exception>... allowedExceptionTypes) throws Exception {
final Set<Class<? extends Exception>> exceptions = new HashSet<>(Arrays.asList(allowedExceptionTypes));
for(int i = 1; i <= maxRetries; i++) {
try {
return function.call();
} catch (Exception e) {
if(exceptions.contains(e.getClass())){
// An exception of an expected type
System.out.println("Attempt [" + i + "/" + maxRetries + "] Caught exception [" + e.getClass() + "]");
// Pause for the delay time
Thread.sleep(delay.toMillis());
}else {
// An unexpected exception type
throw e;
}
}
}
throw new RuntimeException(maxRetries + " retries exceeded");
}