Come implementate un re-try-catch?

Try-catch ha lo scopo di aiutare nella gestione delle eccezioni. Ciò significa che in qualche modo aiuterà il nostro sistema ad essere più robusto: provare a recuperare da un evento inaspettato.

Sospettiamo che qualcosa possa accadere durante l’esecuzione e l’istruzione (invio di un messaggio), quindi viene incluso nel tentativo. Se succede qualcosa di inaspettato, possiamo fare qualcosa: scriviamo il trucco. Non penso che abbiamo chiamato solo per registrare l’eccezione. I cosa il blocco di cattura è destinato a darci l’opportunità di recuperare dall’errore.

Ora, diciamo che recuperiamo dall’errore perché potremmo risolvere ciò che era sbagliato. Potrebbe essere super bello fare un re-try:

try{ some_instruction(); } catch (NearlyUnexpectedException e){ fix_the_problem(); retry; } 

Questo cadrà rapidamente nel ciclo eterno, ma diciamo che fix_the_problem restituisce true, quindi riproviamo. Dato che non c’è nulla di simile in Java, come risolverebbe questo problema? Quale sarebbe il tuo miglior codice di progettazione per risolvere questo?

Questa è come una domanda filosofica, dato che so già che cosa sto chiedendo non è direttamente supportato da Java.

Devi racchiudere il tuo try-catch all’interno di un ciclo while come questo: –

 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; } } 

Ho preso il count e maxTries per evitare l’esecuzione in un ciclo infinito, nel caso in cui l’eccezione continui a verificarsi nel try block .

Soluzione “enterprisy” obbligatoria:

 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); } } } } 

E per chiamare:

 OperationHelper.doWithRetry(5, new Operation() { @Override public void doIt() { //do some stuff } @Override public void handleException(Exception cause) { //recover from the Exception } }); 

Come al solito, il miglior design dipende dalle circostanze particolari. Di solito però, scrivo qualcosa come:

 for (int retries = 0;; retries++) { try { return doSomething(); } catch (SomeException e) { if (retries < 6) { continue; } else { throw e; } } } 

Anche se try/catch while è ben noto e buona strategia voglio suggerirti una chiamata ricorsiva:

 void retry(int i, int limit) { try { } catch (SomeException e) { // handle exception if (i >= limit) { throw e; // variant: wrap the exception, eg throw new RuntimeException(e); } retry(i++, limit); } } 

Puoi usare annotazioni AOP e Java da aspetti di jcabi (sono uno sviluppatore):

 @RetryOnFailure(attempts = 3, delay = 5) public String load(URL url) { return url.openConnection().getContent(); } 

Puoi anche utilizzare annotazioni @Loggable e @LogException .

Il tuo scenario esatto gestito tramite Failsafe :

 RetryPolicy retryPolicy = new RetryPolicy() .retryOn(NearlyUnexpectedException.class); Failsafe.with(retryPolicy) .onRetry((r, f) -> fix_the_problem()) .run(() -> some_instruction()); 

Abbastanza semplice.

Molte di queste risposte sono essenzialmente le stesse. Anche il mio è, ma questa è la forma che mi piace

 boolean completed = false; Throwable lastException = null; for (int tryCount=0; tryCount < config.MAX_SOME_OPERATION_RETRIES; tryCount++) { try { completed = some_operation(); break; } catch (UnlikelyException e) { lastException = e; fix_the_problem(); } } if (!completed) { reportError(lastException); } 

Usa un ciclo while con flag di status locale. Inizializza il flag come false e impostalo su true quando l’operazione ha esito positivo, per esempio sotto:

  boolean success = false; while(!success){ try{ some_instruction(); success = true; } catch (NearlyUnexpectedException e){ fix_the_problem(); } } 

Continuerà a riprovare fino al suo successo.

Se si desidera riprovare solo un certo numero di volte, utilizzare anche un contatore:

  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 } 

Questo proverà al massimo 10 volte se non avrà successo fino a quel momento e uscirà se ha successo prima della mano.

Un modo semplice per risolvere il problema sarebbe quello di avvolgere il try / catch in un ciclo while e mantenere un conteggio. In questo modo è ansible prevenire un ciclo infinito controllando un conteggio rispetto ad altre variabili mantenendo un registro dei guasti. Non è la soluzione più squisita, ma funzionerebbe.

Nel caso in cui sia utile, un paio di altre opzioni da considerare, tutte unite insieme (stopfile invece di tentativi, sleep, continue loop più grandi) sono tutte utili.

  bigLoop: while(!stopFileExists()) { try { // do work break; } catch (ExpectedExceptionType e) { // could sleep in here, too. // another option would be to "restart" some bigger loop, like continue bigLoop; } // ... more work } 

Tutto ciò che Try-Catch fa è permettere al tuo programma di fallire con grazia. In una dichiarazione di cattura, in genere si tenta di registrare l’errore e, se necessario, è ansible eseguire il rollback delle modifiche.

 bool finished = false; while(finished == false) { try { //your code here finished = true } catch(exception ex) { log.error("there was an error, ex"); } } 

Usa un do-while per progettare il blocco di re-try.

 boolean successful = false; int maxTries = 3; do{ try { something(); success = true; } catch(Me ifUCan) { maxTries--; } } while (!successful || maxTries > 0) 

So che ci sono già molte risposte simili qui, e la mia non è molto diversa, ma la pubblicherò comunque perché tratta di un caso / problema specifico.

Quando si ha a che fare con l’ facebook Graph API in PHP a volte si ottiene un errore, ma riprovare immediatamente la stessa cosa darà un risultato positivo (per varie ragioni di Internet magiche che vanno oltre lo scopo di questa domanda). In questo caso non è necessario correggere alcun errore, ma semplicemente riprovare perché c’è stata una sorta di “errore di Facebook”.

Questo codice viene utilizzato immediatamente dopo aver creato una sessione di Facebook:

 //try more than once because sometimes "facebook error" $attempt = 3; while($attempt-- > 0) { // To validate the session: try { $facebook_session->validate(); $attempt = 0; } catch (Facebook\FacebookRequestException $ex) { // Session not valid, Graph API returned an exception with the reason. if($attempt <= 0){ echo $ex->getMessage(); } } catch (\Exception $ex) { // Graph API returned info, but it may mismatch the current app or have expired. if($attempt <= 0){ echo $ex->getMessage(); } } } 

Inoltre, avendo il ciclo for conto alla rovescia fino a zero ( $attempt-- ) è abbastanza facile cambiare il numero di tentativi in ​​futuro.

di seguito è la mia soluzione con un approccio molto semplice!

  while (true) { try { /// Statement what may cause an error; break; } catch (Exception e) { } } 

Non sono sicuro che questo sia il modo “Professionale” per farlo e non sono del tutto sicuro che funzioni per tutto.

 boolean gotError = false; do { try { // Code You're Trying } catch ( FileNotFoundException ex ) { // Exception gotError = true; } } while ( gotError = true ); 

https://github.com/tusharmndr/retry-function-wrapper/tree/master/src/main/java/io

 int MAX_RETRY = 3; RetryUtil.retry(MAX_RETRY,() -> { //Function to retry return true; }); 

Ecco un approccio riutilizzabile e più generico per Java 8+ che non richiede librerie esterne:

 public interface IUnreliable { void tryRun ( ) throws T; } public static  void retry (int retryCount, IUnreliable runnable) throws T { for (int retries = 0;; retries++) { try { runnable.tryRun(); return; } catch (Exception e) { if (retries < retryCount) { continue; } else { throw e; } } } } 

Uso:

 @Test public void demo() throws IOException { retry(3, () -> { new File("/tmp/test.txt").createNewFile(); }); }