你如何實(shí)現(xiàn)重新嘗試?Try-catch旨在幫助進(jìn)行異常處理。這意味著它將以某種方式幫助我們的系統(tǒng)更加健壯:嘗試從意外事件中恢復(fù)。我們懷疑在執(zhí)行和指令(發(fā)送消息)時(shí)可能會(huì)發(fā)生某些事情,因此它會(huì)被包含在try中。如果發(fā)生幾乎意外的事情,我們可以做點(diǎn)什么:我們寫下了捕獲。我認(rèn)為我們沒有打電話來記錄異常。我認(rèn)為catch塊意味著讓我們有機(jī)會(huì)從錯(cuò)誤中恢復(fù)?,F(xiàn)在,假設(shè)我們可以從錯(cuò)誤中恢復(fù),因?yàn)槲覀兛梢孕迯?fù)錯(cuò)誤。重做是非常好的:try{ some_instruction(); }catch (NearlyUnexpectedException e){
fix_the_problem();
retry;}這將很快落入永恒循環(huán),但是假設(shè)fix_the_problem返回true,那么我們重試。鑒于Java中沒有這樣的東西,你將如何解決這個(gè)問題?解決這個(gè)問題的最佳設(shè)計(jì)代碼是什么?這就像一個(gè)哲學(xué)問題,因?yàn)槲乙呀?jīng)知道我所要求的并不是Java直接支持的。
3 回答

慕無忌1623718
TA貢獻(xiàn)1744條經(jīng)驗(yàn) 獲得超4個(gè)贊
你需要將你的try-catch
內(nèi)部包圍在這樣的while
循環(huán)中: -
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; }}
我已經(jīng)采取count
并maxTries
避免遇到無限循環(huán),以防異常繼續(xù)發(fā)生在你的try block
。

蝴蝶刀刀
TA貢獻(xiàn)1801條經(jīng)驗(yàn) 獲得超8個(gè)贊
這是一個(gè)古老的問題,但解決方案仍然具有現(xiàn)實(shí)意義。這是我在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; }}
我們有一個(gè)測試用例如:
@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(); }}
添加回答
舉報(bào)
0/150
提交
取消