目录
第十七章 Try与异常处理
1- 异常的抛出和捕获
Scala 的异常处理机制与 Java非常相似, 但也有一些区别 ;
1. 异常抛出
- Scala 使用
throw
关键字抛出异常, 和 Java一样 ; - Scala 没有"受检异常" (checked Exception) 的概念 ; 不需要声明函数可能抛出的异常 ;
示例:
scala
def divide(a: Int, b: Int): Int = {
if (b == 0) {
throw new IllegalArgumentException("Divisor cannot be zero!!!")
}
a / b
}
scala
def main(args: Array[String]): Unit = {
val res = divide(10, 0)
println(res) // Output: java.lang.IllegalArgumentException: Divisor cannot be zero!!!
}
2. 异常捕获
- Scala使用
try...catch...finally
结构捕获异常, 与 Java 类似, 但catch
部分使用模式匹配来处理不同类型的异常 ; finally
子句是可选的, 用于执行无论是否发生异常都需要执行的代码, 例如关闭资源 ;
示例:
scala
def divide(a: Int, b: Int): Int = {
if (b == 0) {
throw new IllegalArgumentException("Divisor cannot be zero!!!")
}
a / b
}
scala
try {
val res = divide(10, 0)
println(res)
} catch {
case e: IllegalArgumentException => println(s"捕获到异常: ${e.getMessage}") // Output: 捕获到异常: Divisor cannot be zero!!!
} finally {
println("finally: 无论是否发生异常都会执行;") // Output: finally: 无论是否发生异常都会执行;
}
说明:
- try块: 包含可能抛出异常的代码 ;
- catch块: 捕获异常; Scala的
catch
块是一个模式匹配的例子, 每个case
分支处理不同类型的异常 ; - finally块: 包含总是会执行的代码 (不管是否抛出异常) ; 通常用于释放资源, 如关闭文件或数据库连接 ;
Scala 的异常处理机制结合了 Java的 try...catch...finally
结构和自身的模式匹配, 提供了更灵活、更强大的异常处理能力 ;
同时, Try
类型为开发者提供了更函数式的异常处理方式, 使代码更简洁易懂 .
2- 函数式的错误处理
在Scala中, 函数式编程风格推崇使用不可变数据和纯函数, 尽量避免副作用和异常 ;但实际应用中, 异常难以完全避免 ;
Scala提供了 Try
类型, 让我们可以用更函数式的方法来处理异常 ;
1. Try
类型
Try
是 Scala中用于表示可能抛出异常的操作的结果类型 ; 它有两个子类:
Success[T]
: 表示操作成功, 包含成功的结果值, 类型为T
;Failure[T]
: 表示操作失败, 包含抛出的异常信息, 类型为Throwable
;
2. 使用 Try
可以使用 Try
的伴生对象的 apply
方法将可能抛出异常的代码块包起来 :
示例:
scala
import scala.util.Try
def riskyOperation(x: Int): Int = {
if (x < 0) {
throw new IllegalArgumentException("x must be positive")
} else x * 2
}
val result: Try[Int] = Try(riskyOperation(-1))
println(result) // Output: Failure(java.lang.IllegalArgumentException: x must be positive)
val result2: Try[Int] = Try(riskyOperation(5))
println(result2) // Output: Success(10)
3. 处理 Try
结果
可以用模式匹配的方式处理 Try
的结果:
scala
import scala.util.{Try, Success, Failure}
def riskyOperation(x: Int): Int = {
if (x < 0) {
throw new IllegalArgumentException("x must be positive")
} else x * 2
}
val result1: Try[Int] = Try(riskyOperation(-1))
result1 match {
case Success(value) => println(s"Success: $value")
case Failure(exception) => println(s"Failure: ${exception.getMessage}")
}
// Output: Failure: x must be positive
val result2: Try[Int] = Try(riskyOperation(5))
result2 match {
case Success(value) => println(s"Success: $value")
case Failure(exception) => println(s"Failure: ${exception.getMessage}")
}
// Output: Success: 10
4. Try
的常用方法
Try
提供了一些方便地方法来处理异常, 例如:
map
: 如果Try
是Success
, 则对成功的结果值应用函数, 并返回新的Try
; 如果是Failure
, 则直接返回Failure
;flatMap
: 与map
类似, 但函数需要返回一个Try
类型的值 ;recover
: 如果Try
是Failure
, 则应用偏函数来处理异常, 并返回新的Try
; 如果是Success
, 则直接返回Success
;getOrElse
: 如果Try
是Success
, 则返回成功的结果值; 如果是Failure
, 则返回默认值 ;
5. Try
的优势
- 避免
try...catch
语句的嵌套, 使代码更简洁易读 ; - 将异常处理融入函数式编程风格, 可以使用
map
、flatMap
等高阶函数 ; - 更容易组合和传递可能抛出异常的操作的结果 ;
总结
Try
类型是 Scala中函数式异常处理的重要工具, 它让挖煤可以用更优雅、更简洁的方式来处理异常, 使代码更易于理解和维护 .