You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala从2.12.4升级到2.12.18后try-catch编译报错求助

问题描述

我有一个会在Future中抛出自定义异常的方法,调用方代码如下:

try {
  Future<Option<type>> futureRet = doWork(input);
  Option<type> res = Await$.MODULE$.result(futureRet, Duration.apply("30s"));
} catch (CustomException e) {
  return customExceptionHandler(e);
} catch (Exception e) {
  return handleException(request, e);
}

可能返回Future.failed()的方法代码如下:

override def doWork(
  input: String
): Future[Option[ReturnType]] = {
  if (!input.isEmpty) {
    completeWork(input)
  } else {
    Future.failed(CustomException("bad input"))
  }
}

CustomException的定义如下:

case class CustomException(er: String) extends Exception(s"error $er")

上述代码在Scala 2.12.4中运行正常,但升级到Scala 2.12.18后出现编译错误:"exception is never thrown in the corresponding try block"。有趣的是,即使移除catch (CustomException e)块,当doWork抛出异常时,调试器显示该异常为CustomException类型,但仍会出现编译错误。请问该如何修复?Scala版本间有哪些变化导致了这个问题?

问题原因

Scala 2.12.10及后续版本对Await.result的编译检查做了严格优化。旧版本中,编译器不会严格校验Future.failed携带的异常类型是否会被Await.result直接抛出;但新版本里,编译器会基于Await.result的方法签名(声明仅抛出InterruptedException和TimeoutException)做静态检查,判定try块内不会抛出CustomException,因此触发编译错误。

实际上,Await.result会把Future内部的异常包装成ExecutionException抛出,调试器中看到的CustomException是ExecutionException的cause,并非直接抛出的顶层异常。旧版本编译器未严格校验这一逻辑,新版本补上了该校验规则。

修复方案

需要捕获ExecutionException,从中提取内部的CustomException进行处理,修改后的调用方代码示例如下:

try {
  val futureRet = doWork(input)
  val res = Await.result(futureRet, Duration.apply("30s"))
} catch {
  case e: ExecutionException if e.getCause.isInstanceOf[CustomException] =>
    val customEx = e.getCause.asInstanceOf[CustomException]
    customExceptionHandler(customEx)
  case e: InterruptedException | e: TimeoutException =>
    handleException(request, e)
  case e: Exception =>
    handleException(request, e)
}

也可以用模式匹配直接提取异常cause简化逻辑:

try {
  val res = Await.result(doWork(input), 30.seconds)
} catch {
  case ExecutionException(customEx: CustomException) =>
    customExceptionHandler(customEx)
  case otherEx: Exception =>
    handleException(request, otherEx)
}

另外注意:原doWork方法中写的Future.failed(customExceptionHandler("bad input"))存在逻辑错误,应该改为Future.failed(CustomException("bad input")),否则是把异常处理后的结果包装成了异常,需要修正。

内容的提问来源于stack exchange,提问作者user888270

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 10:02:22