¿Cómo implementas un re-try-catch?

Try-catch está destinado a ayudar en el manejo de excepciones. Esto significa de alguna manera que ayudará a nuestro sistema a ser más robusto: trate de recuperarse de un evento inesperado.

Sospechamos que algo podría suceder al ejecutar e instruir (enviando un mensaje), por lo que queda incluido en el bash. Si sucede algo inesperado, podemos hacer algo: escribimos el truco. No creo que hayamos llamado para solo registrar la excepción. Creo que el bloque de catch pretende darnos la oportunidad de recuperarnos del error.

Ahora, digamos que nos recuperamos del error porque pudimos arreglar lo que estaba mal. Podría ser súper agradable hacer una nueva prueba:

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

Esto caería rápidamente en el bucle eterno, pero digamos que el fix_the_problem devuelve true, luego volvemos a intentarlo. Dado que no existe tal cosa en Java, ¿cómo resolverías TU problema? ¿Cuál sería tu mejor código de diseño para resolver esto?

Esto es como una pregunta filosófica, dado que ya sé que lo que estoy pidiendo no es respaldado directamente por Java.

Debes encerrar tu try-catch dentro de un ciclo while como este:

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

He tomado count y maxTries para evitar ejecutar en un bucle infinito, en caso de que la excepción siga ocurriendo en su try block .

Solución “emprendedora” obligatoria:

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

Y para llamar:

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

Como de costumbre, el mejor diseño depende de las circunstancias particulares. Sin embargo, normalmente escribo algo así como:

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

Aunque try/catch while es bien conocida y una buena estrategia, quiero sugerirle una llamada recursiva:

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

Puede usar anotaciones AOP y Java desde jcabi-aspects (soy desarrollador):

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

También puede usar las anotaciones @Loggable y @LogException .

Su situación exacta manejada a través de Failsafe :

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

Bastante simple.

La mayoría de estas respuestas son esencialmente las mismas. El mío también, pero esta es la forma que me gusta

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

Use un ciclo while con indicador de status local. Inicialice el indicador como false y configúrelo como true cuando la operación sea exitosa, por ejemplo, a continuación:

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

Esto seguirá reintentando hasta que sea exitoso.

Si desea volver a intentar solo cierto número de veces, utilice un contador también:

  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 } 

Esto intentará un máximo de 10 veces si no tiene éxito hasta que una tecla salga si es exitosa antes de la mano.

Una forma simple de resolver el problema sería ajustar el try / catch en un ciclo while y mantener un conteo. De esta forma, podría evitar un ciclo infinito al verificar un recuento contra alguna otra variable mientras mantiene un registro de sus fallas. No es la solución más exquisita, pero funcionaría.

En caso de que sea útil, un par de opciones más a tener en cuenta, todas juntas (archivo stop en lugar de rebashs, dormir, continuar bucle más grande) posiblemente todas sean útiles.

  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 } 

Todo lo que hace Try-Catch es permitir que su progtwig falle con elegancia. En una statement catch, generalmente intentas registrar el error y quizás revertir los cambios si es necesario.

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

Use un do-while para diseñar el bloque de rebashs.

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

Sé que ya hay muchas respuestas similares aquí, y la mía no es muy diferente, pero la publicaré de todos modos porque se trata de un caso / problema específico.

Al tratar con la facebook Graph API en PHP a veces se obtiene un error, pero volver a intentar lo mismo dará un resultado positivo (por varias razones mágicas de Internet que están más allá del scope de esta pregunta). En este caso, no es necesario corregir ningún error, sino simplemente volver a intentarlo porque hubo algún tipo de “error de Facebook”.

Este código se usa inmediatamente después de crear una sesión de 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(); } } } 

Además, al hacer que la cuenta for bucle sea cero ( $attempt-- ), es bastante fácil cambiar el número de bashs en el futuro.

¡lo que sigue es mi solución con un enfoque muy simple!

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

No estoy seguro si esta es la manera “profesional” de hacerlo y no estoy del todo seguro de si funciona para todo.

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

Aquí un enfoque reutilizable y más genérico para Java 8+ que no requiere bibliotecas externas:

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