你如何实现重新尝试?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
提交
取消