关于java:包含具有不同签名的通用回调函数

wrapping around generic callback function with different signatures

我正在努力学习scala,到目前为止它似乎是一种非常强大的语言,但有些事情似乎很难实现,可能只是我的学习曲线。我在网上研究了几天,但找不到一个好的解决方案来做我想做的事情。

我有多个方法(具有不同的签名,包括返回类型),我希望用重试逻辑包装这些方法。

我想在方法成功之前,一直按预先定义的次数调用一个方法。

下面是一个例子:

1
2
3
4
5
def downloadLocal(memory: Boolean, userName: Name, version: Int): Int

def downloadRemote(
  memory: Boolean, userName: Name, masterNodeId: String, masterNodeId: String
): Pair(Int, Int)

我想在重试逻辑中包装这两个方法。下面是我对重试逻辑的尝试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
trait WithRetry{
  def withRetry(retry :Int){
    try{
      callBack
    }catch{
      case exception:Throwable =>
        if(retry>0){
          logger.warn(exec+" method failed with an exception. retry number is:" + retry);
          logger.warn(exception);
          withRetry(retry-1)
        }
        else{
          throw exception
        }
    }
  }
  def callBack():Any
}

我遇到的问题是,在重试逻辑中找不到一种清晰的方法来包装我的方法(downloadRemotedownloadLocal

有什么建议/想法吗?


您只需定义一个通用函数:

1
2
3
4
5
6
7
8
9
10
11
12
import scala.util.{Try, Success, Failure}

def retry[T](times: Int)(block: => T): T = Try(block) match {
  case Success(result) => result
  case Failure(e) =>
    if (times > 0) {
      logger.warn(s"method failed with an exception, retry #$times")
      logger.warn(exception)
      retry(times - 1)(block)
    }
    else throw e
}

这是一个尾部递归函数,因此它与调用Java中的for循环中的函数一样有效。

然而,更惯用的scala将返回Try

1
2
3
4
5
6
7
8
def retry2[T](times: Int)(block: => T): Try[T] =
  Try(block) match {
    case Failure(e) if (times > 0) =>
      logger.warn(s"method failed with an exception, retry #$times")
      logger.warn(exception)
      retry2(times - 1)(block)
    case other => other
  }

两个版本都可以用作:

1
2
3
4
5
6
7
8
9
10
11
12
13
def failRandomly: Int =
  if (scala.util.Random.nextInt < 0.80) throw new Exception("boom")
  else 1

scala> retry(2)(failRandomly)
res0: Int = 1
scala> retry(2)(failRandomly)
java.lang.Exception: boom  // ...

scala> retry2(2)(failRandomly)
res1: scala.util.Try[Int] = Success(1)
scala> retry2(2)(failRandomly)
res2: scala.util.Try[Int] = Failure(java.lang.Exception: boom)