你如何实现重新尝试?Try-catch旨在帮助进行异常处理。这意味着它将以某种方式帮助我们的系统更加健壮:尝试从意外事件中恢复。我们怀疑在执行和指令(发送消息)时可能会发生某些事情,因此它会被包含在try中。如果发生几乎意外的事情,我们可以做点什么:我们写下了捕获。我认为我们没有打电话来记录异常。我认为catch块意味着让我们有机会从错误中恢复。现在,假设我们可以从错误中恢复,因为我们可以修复错误。重做是非常好的:try{ some_instruction(); }catch (NearlyUnexpectedException e){
fix_the_problem();
retry;}这将很快落入永恒循环,但是假设fix_the_problem返回true,那么我们重试。鉴于Java中没有这样的东西,你将如何解决这个问题?解决这个问题的最佳设计代码是什么?这就像一个哲学问题,因为我已经知道我所要求的并不是Java直接支持的。
3 回答
慕无忌1623718
TA贡献1744条经验 获得超4个赞
你需要将你的try-catch内部包围在这样的while循环中: -
int count = 0;int maxTries = 3;while(true) {
try {
// Some Code
// break out of loop, or return, on success
} catch (SomeException e) {
// handle exception
if (++count == maxTries) throw e;
}}我已经采取count并maxTries避免遇到无限循环,以防异常继续发生在你的try block。
蝴蝶刀刀
TA贡献1801条经验 获得超8个赞
这是一个古老的问题,但解决方案仍然具有现实意义。这是我在Java 8中的通用解决方案,不使用任何第三方库:
public interface RetryConsumer<T> {
T evaluate() throws Throwable;}public interface RetryPredicate<T> {
boolean shouldRetry(T t);}public class RetryOperation<T> {
private RetryConsumer<T> retryConsumer;
private int noOfRetry;
private int delayInterval;
private TimeUnit timeUnit;
private RetryPredicate<T> retryPredicate;
private List<Class<? extends Throwable>> exceptionList;
public static class OperationBuilder<T> {
private RetryConsumer<T> iRetryConsumer;
private int iNoOfRetry;
private int iDelayInterval;
private TimeUnit iTimeUnit;
private RetryPredicate<T> iRetryPredicate;
private Class<? extends Throwable>[] exceptionClasses;
private OperationBuilder() {
}
public OperationBuilder<T> retryConsumer(final RetryConsumer<T> retryConsumer) {
this.iRetryConsumer = retryConsumer;
return this;
}
public OperationBuilder<T> noOfRetry(final int noOfRetry) {
this.iNoOfRetry = noOfRetry;
return this;
}
public OperationBuilder<T> delayInterval(final int delayInterval, final TimeUnit timeUnit) {
this.iDelayInterval = delayInterval;
this.iTimeUnit = timeUnit;
return this;
}
public OperationBuilder<T> retryPredicate(final RetryPredicate<T> retryPredicate) {
this.iRetryPredicate = retryPredicate;
return this;
}
@SafeVarargs
public final OperationBuilder<T> retryOn(final Class<? extends Throwable>... exceptionClasses) {
this.exceptionClasses = exceptionClasses;
return this;
}
public RetryOperation<T> build() {
if (Objects.isNull(iRetryConsumer)) {
throw new RuntimeException("'#retryConsumer:RetryConsumer<T>' not set");
}
List<Class<? extends Throwable>> exceptionList = new ArrayList<>();
if (Objects.nonNull(exceptionClasses) && exceptionClasses.length > 0) {
exceptionList = Arrays.asList(exceptionClasses);
}
iNoOfRetry = iNoOfRetry == 0 ? 1 : 0;
iTimeUnit = Objects.isNull(iTimeUnit) ? TimeUnit.MILLISECONDS : iTimeUnit;
return new RetryOperation<>(iRetryConsumer, iNoOfRetry, iDelayInterval, iTimeUnit, iRetryPredicate, exceptionList);
}
}
public static <T> OperationBuilder<T> newBuilder() {
return new OperationBuilder<>();
}
private RetryOperation(RetryConsumer<T> retryConsumer, int noOfRetry, int delayInterval, TimeUnit timeUnit,
RetryPredicate<T> retryPredicate, List<Class<? extends Throwable>> exceptionList) {
this.retryConsumer = retryConsumer;
this.noOfRetry = noOfRetry;
this.delayInterval = delayInterval;
this.timeUnit = timeUnit;
this.retryPredicate = retryPredicate;
this.exceptionList = exceptionList;
}
public T retry() throws Throwable {
T result = null;
int retries = 0;
while (retries < noOfRetry) {
try {
result = retryConsumer.evaluate();
if (Objects.nonNull(retryPredicate)) {
boolean shouldItRetry = retryPredicate.shouldRetry(result);
if (shouldItRetry) {
retries = increaseRetryCountAndSleep(retries);
} else {
return result;
}
} else {
// no retry condition defined, no exception thrown. This is the desired result.
return result;
}
} catch (Throwable e) {
retries = handleException(retries, e);
}
}
return result;
}
private int handleException(int retries, Throwable e) throws Throwable {
if (exceptionList.contains(e.getClass()) || (exceptionList.isEmpty())) {
// exception is excepted, continue retry.
retries = increaseRetryCountAndSleep(retries);
if (retries == noOfRetry) {
// evaluation is throwing exception, no more retry left. Throw it.
throw e;
}
} else {
// unexpected exception, no retry required. Throw it.
throw e;
}
return retries;
}
private int increaseRetryCountAndSleep(int retries) {
retries++;
if (retries < noOfRetry && delayInterval > 0) {
try {
timeUnit.sleep(delayInterval);
} catch (InterruptedException ignore) {
Thread.currentThread().interrupt();
}
}
return retries;
}}我们有一个测试用例如:
@Testpublic void withPredicateAndException() {
AtomicInteger integer = new AtomicInteger();
try {
Integer result = RetryOperation.<Integer>newBuilder()
.retryConsumer(() -> {
int i = integer.incrementAndGet();
if (i % 2 == 1) {
throw new NumberFormatException("Very odd exception");
} else {
return i;
}
})
.noOfRetry(10)
.delayInterval(10, TimeUnit.MILLISECONDS)
.retryPredicate(value -> value <= 6)
.retryOn(NumberFormatException.class, EOFException.class)
.build()
.retry();
Assert.assertEquals(8, result.intValue());
} catch (Throwable throwable) {
Assert.fail();
}}添加回答
举报
0/150
提交
取消
