Scala 异常捕获怎么写:从 try/catch 到 Try、getOrElse 与 recover

不晚
不晚
发布时间:2026-08-23| 7人浏览过
原创

前言

在 Scala 里,异常处理语法和 Java 很接近,但一旦进入 RPC、Future 或其他异步链路,单纯依赖 try/catch 往往会让分支散落、代码变重。本文从基础捕获写起,再过渡到 scala.util.Try 的几种常见写法,帮助你判断:什么时候直接捕获异常,什么时候把失败显式包装成 Success/Failure,以及默认值和定向恢复该怎么落地。

在 Scala 里,异常处理语法和 Java 很接近,但一旦进入 RPC、Future 或其他异步链路,单纯依赖 try/catch 往往会让分支散落、代码变重。本文从基础捕获写起,再过渡到 scala.util.Try 的几种常见写法,帮助你判断:什么时候直接捕获异常,什么时候把失败显式包装成 Success/Failure,以及默认值和定向恢复该怎么落地。

传统写法:Scala 里的 try/catch/finally

Scala 支持和 Java 类似的 try、catch、finally 语义。不同点在于,catch 块里通常使用 case 来匹配异常类型。

object TestFuture {
  def main(args: Array[String]): Unit = {
    var num = 1
    try {
      num = 100/0  // 生成算数异常
    } catch {
      // :type 表示是否匹配 type 类型
      case e: ArithmeticException => println(e.getMessage)
      case e: RuntimeException => println(e.getMessage)
      // ... 其他方式一并用 case 处理
    } finally {
      // .. 不论是否处理异常,都会执行这个代码块
      println("run finally")
    }
  }  
}

这段代码会触发除零异常,因此输出结果如下:

/ by zero
run finally

为什么这种方式不总是最优

如果只是处理一个同步代码块,try/catch 已经足够直接。但在 RPC、异步调用或多层组合逻辑里,异常分支容易和业务分支交织在一起,代码会越来越难读。原文也明确指出,这类场景更推荐使用 Try 来承载成功或失败结果。

用 Try 包装结果:Success 和 Failure

Try 的核心思路是:把一次操作的结果显式表示为成功或失败,而不是只在出错时抛异常。最基础的写法如下:

import scala.util.{Failure, Success, Try}

object TestFuture {
  def main(args: Array[String]): Unit = {
    divide(1, 2) match {
      case Success(num) => println(num)
      case Failure(e) => println(e.getMessage)
    }

    divide(1, 0) match {
      case Success(num) => println(num)
      case Failure(e) => println(e.getMessage)
    }
  }

  def divide(a: Int, b: Int): Try[Int] = {
    b match {
      case 0 => Failure(new ArithmeticException(s"$a divide by zero"))
      case _ => Success(a / b)
    }
  }
}

输出结果:

0
1 divide by zero

这里有两个关键点:

  • 操作成功时,返回 Success[T]。
  • 操作失败时,返回由 Failure 包装的异常对象。

也就是说,调用方不需要在外层再写一层异常捕获,而是可以通过模式匹配把成功和失败分支并列写清楚。

失败时给默认值:getOrElse

如果你的目标不是细分异常,而是“失败就兜底”,那 getOrElse 会更简洁。原文示例如下:

import scala.util.{Failure, Success, Try}

object TestFuture {
  def main(args: Array[String]): Unit = {
    val result1= divide(6, 2) getOrElse -1
    val result2 = divide(6, 0) getOrElse -1
    println(s"result1 = $result1, result2 = $result2")
  }

  def divide(a: Int, b: Int): Try[Int] = {
    b match {
      case 0 => Failure(new ArithmeticException(s"$a divide by zero"))
      case _ => Success(a / b)
    }
  }
}

输出结果:

result1 = 3, result2 = -1

这个例子表达得很明确:

  • divide(6, 2) 成功,结果是 3。
  • divide(6, 0) 失败,于是直接回退到默认值 -1。

当业务只关心“能不能给出一个可继续使用的结果”时,这种写法通常比手动匹配 Success/Failure 更省事。

只恢复特定异常:recover

还有一种常见需求是:某些异常希望单独处理,其他情况再交给默认逻辑。这个时候可以使用 recover。

import scala.util.{Failure, Success, Try}

object TestFuture {
  def main(args: Array[String]): Unit = {
    val result = divide(1, 2) recover {
      case e: ArithmeticException => println(e.getMessage)
      case e: RuntimeException => println(e.getMessage)
      case _ => "recover failed"
    }
    println(result.get)
  }

  def divide(a: Int, b: Int): Try[Int] = {
    b match {
      case 0 => Failure(new ArithmeticException(s"$a divide by zero"))
      case -1 => Failure(new RuntimeException("runtime failed"))
      case _ => Success(a / b)
    }
  }
}

这里要特别注意原文提到的一点:如果没有异常,结果仍然是 Success[T],只有失败时才会进入 recover 的逻辑。

使用 recover 时要看清返回值类型

recover 的作用不是单纯“打印错误”,而是把失败结果恢复成一个新的成功结果。因此你在 case 里返回的值,应该和原来的成功类型保持一致,便于后续继续使用。

从思路上看,recover 适合这种场景:异常可以分类处理,而且其中一部分异常有明确补偿策略。

怎么选:try/catch 还是 Try

结合这几种写法,可以这样理解:

用信息图展示 Scala 中 try/catch 与 Try 的选择关系,以及 Success、Failure、默认值处理之间的对应路径。
Scala 异常处理方式选择图把同步捕获、结果包装、默认值回退和定向恢复放到同一张图里,更容易判断不同场景该选哪种写法。
  • 临时处理单个同步代码块,使用 try/catch/finally 足够直接。
  • 希望把成功与失败统一建模,优先考虑 Try。
  • 只要兜底结果,用 getOrElse。
  • 只想恢复某些特定异常,用 recover。

对 Scala 项目来说,Try 最大的价值不只是“能处理异常”,而是它把异常从隐式控制流,变成了可以匹配、组合和传递的显式结果。这也是它在异步和链式调用场景里更容易维护的原因。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。