我在 scala 中遇到了一些非常奇怪的行为。我编写了一个通用方法,该方法将容易出错的代码和“有效异常”列表作为参数,它应该执行代码,同时在抛出“有效异常”时重试代码。
该方法效果很好,我在几个地方使用它。
但是,其中一个方法调用在编译时失败了。
原因是异常列表的初始化。
我已经在 REPL 中尝试过,以确保没有其他原因,您可以自己查看结果:
me@my-lap:~$ scala -cp /path/to/maven/repository/org/apache/httpcomponents/httpclient/4.1.1/httpclient-4.1.1.jar:/path/to/maven/repository/commons-httpclient/commons-httpclient/3.1/commons-httpclient-3.1.jar:/path/to/maven/repository/me/my-utils/1.0-SNAPSHOT/my-utils-1.0-SNAPSHOT.jar:/path/to/maven/repository/org/apache/httpcomponents/httpcore/4.1/httpcore-4.1.jar
Welcome to Scala version 2.9.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_17).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import org.apache.http.conn.{HttpHostConnectException,ConnectTimeoutException}
import org.apache.http.conn.{HttpHostConnectException, ConnectTimeoutException}
scala> import me.util.exceptions.RetryException
import me.util.exceptions.RetryException
scala> val validEx = classOf[ConnectTimeoutException] :: classOf[RetryException] :: classOf[HttpHostConnectException] :: Nil
<console>:9: error: inferred type arguments [java.lang.Class[_ >: _1 with org.apache.http.conn.ConnectTimeoutException <: java.lang.Exception]] do not conform to method ::'s type parameter bounds [B >: java.lang.Class[_ >: org.apache.http.conn.HttpHostConnectException with me.util.exceptions.RetryException <: java.lang.Exception]]
val validEx = classOf[ConnectTimeoutException] :: classOf[RetryException] :: classOf[HttpHostConnectException] :: Nil
^
从所有 3 种异常类型初始化列表时,代码失败并出现这个奇怪的错误。所以我尝试使用这 3 个中的 2 个异常的每个子集进行初始化:
scala> val validEx = classOf[ConnectTimeoutException] :: classOf[RetryException] :: Nil
validEx: List[java.lang.Class[_ >: me.util.exceptions.RetryException with org.apache.http.conn.ConnectTimeoutException <: java.lang.Exception]] = List(class org.apache.http.conn.ConnectTimeoutException, class me.util.exceptions.RetryException)
scala> val validEx = classOf[ConnectTimeoutException] :: classOf[HttpHostConnectException] :: Nil
validEx: List[java.lang.Class[_ >: org.apache.http.conn.HttpHostConnectException with org.apache.http.conn.ConnectTimeoutException <: java.io.IOException]] = List(class org.apache.http.conn.ConnectTimeoutException, class org.apache.http.conn.HttpHostConnectException)
scala> val validEx = classOf[RetryException] :: classOf[HttpHostConnectException] :: Nil
validEx: List[java.lang.Class[_ >: org.apache.http.conn.HttpHostConnectException with me.util.exceptions.RetryException <: java.lang.Exception]] = List(class me.util.exceptions.RetryException, class org.apache.http.conn.HttpHostConnectException)
它奏效了!我还尝试使用List()
而不是使用::
运算符来创建所有 3 种异常类型的列表。它也有效:
scala> val validEx = List(classOf[ConnectTimeoutException], classOf[RetryException], classOf[HttpHostConnectException])
validEx: List[java.lang.Class[_ >: org.apache.http.conn.HttpHostConnectException with me.util.exceptions.RetryException with org.apache.http.conn.ConnectTimeoutException <: java.lang.Exception]] = List(class org.apache.http.conn.ConnectTimeoutException, class me.util.exceptions.RetryException, class org.apache.http.conn.HttpHostConnectException)
顺便说一句,实现RetryException
是:
class RetryException extends Exception {}
那么为什么会发生呢?它是scala::
运算符的错误吗?
以及为什么编译器不能推断出比以下更好的类型:(List[java.lang.Class[_ >: org.apache.http.conn.HttpHostConnectException with me.util.exceptions.RetryException with org.apache.http.conn.ConnectTimeoutException <: java.lang.Exception]]
我的方法除了类型的参数:validExceptions: List[Class[_ <: java.lang.Throwable]]
这是一种更简洁的类型。除了编译器之外,我会想出类似的东西:List[Class[_ <: java.lang.Exception]]
(我在 ubuntu 12.04 64bit 上运行 Scala 版本 2.9.2(Java7 oracle 1.7.0_17)