有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

trycatch块中的java递归调用以重试N次

我有一个常规的、非静态的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++;
   }
}

首先,来自try/catch块的递归是否正确?还有,有没有更好的方法

我不能使sendMail方法成为静态的,现有代码中有太多对它的引用


共 (3) 个答案

  1. # 1 楼答案

    标准的递归解决方案是将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);
       }
    }
    

    循环将是更惯用的写作方式

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

    按照原始问题的精神,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();
    }
    
  2. # 2 楼答案

    如果您只是将代码包装在重试循环中会怎么样:

    public void sendMail(List<String> params) {
      for (int attempt = 0; attempt < 3; attempt++)
       try {
           //...
    
           if (<some success condition>)
              return;
       }
       catch (Exception e) {
           log.info(e);
       }
    }
    
  3. # 3 楼答案

    您的重试从一开始就不会起作用,因为在每个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?
        } 
      }
    }
    

    这个解决方案比使用递归要干净得多,因为如果您想多次重试,最终会出现堆栈溢出错误。它还使sendMail函数的响应保持简单,并避免向其他简单方法中添加复杂的重试逻辑

    此外,如果您最终不得不以相同的方式使其他方法可重试,那么将重试逻辑抽象为某种执行器服务将更容易