在try-catch块中递归调用重试N次

gen*_* b. 4 java recursion

我有一个常规的非静态sendMail方法,有时可能会失败。我需要捕获任何错误并重试该方法 N 次。我不确定我做的是否正确,而且还有一个编译错误:

public void sendMail(List<String> params) {

   try {
       //...

       static int retrycount = 0; // static not allowed here (but need to keep static var for recursion)
       int maxretries = 3;
   }
   catch (Exception e) {
       log.info(e);
       // Recursion to retry
       sendMail(params);
       retrycount++;
   }
}
Run Code Online (Sandbox Code Playgroud)

首先,try/catch 块的递归是否正确?另外,有更好的方法吗?

我无法使该sendMail方法成为静态方法,现有代码中对其的引用太多。

Ada*_*dam 5

你的重试一开始就不会起作用,因为在每个 try 块中你都将 retrycount 设置为 0。

您可能最好抛出异常而不是捕获异常。然后使用某种 while 循环直到完成,可能在重试之间有可配置的延迟。或者,如果您使用 Spring,则有注释Retryable

void someMethod(){
  int attempts = 0;
  while(attemps <= 3){
    try {
      sendMail(...);
      break;
    } catch (Exception e){
      attempts++;
      // Log failed to send mail or something meaningful, maybe add a delay here?
    } 
  }
}
Run Code Online (Sandbox Code Playgroud)

这个解决方案比使用递归要干净得多,就好像您想重试多次一样,最终您会得到堆栈溢出错误。它还使 sendMail 函数的职责保持简单,并避免向原本简单的方法添加复杂的重试逻辑。

另外,如果您最终必须以相同的方式使其他方法可重试,那么将重试逻辑抽象到某种处理所有问题的执行程序服务中会更容易。


Tom*_*ine 5

标准递归解决方案是添加retryCount作为参数。

public void sendMail(List<String> params) {
    sendMail(params, 0);
}
private void sendMail(List<String> params, int retryCount) {

   try {
       //...

       int maxRetries = 3;
   } catch (Exception e) {
       log.info(e);
       // Recursion to retry
       sendMail(params, retryCount+1);
   }
}
Run Code Online (Sandbox Code Playgroud)

循环是更惯用的编写方式。

public void sendMail(List<String> params) {
    int maxTries = 4;
    for (int tryCount=0; tryCount<maxTries; ++tryCount) {
        try {
            //...
            break;
        } catch (Exception e) {
            log.info(e);
            // continue to retry
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

本着最初问题的精神,retryCount可以将 保留为引入对象内的字段。使用匿名内部类来做到这一点是最简单的(虽然有点晦涩)。

public void sendMail(List<String> params) {
    int maxTries = 4;
    new Object() {
        int tryCount = 0;
        public void sendMail() {
            try {
                //...
            } catch (Exception e) {
                log.info(e);
                // Recursion to retry
                if (tryCount < maxTries) {
                    ++tryCount;
                    sendMail();
                }
            }
        }
    }.sendMail();
}
Run Code Online (Sandbox Code Playgroud)