Skip to content

Scala 异常处理

异常处理是程序健壮性的重要保障。Scala 提供了多种异常处理机制,包括传统的 try-catch、函数式的 Try 类型,以及现代的错误处理模式。

基本异常处理

try-catch-finally

scala
import scala.util.{Try, Success, Failure}
import java.io.{FileReader, BufferedReader, IOException}

object BasicExceptionHandling {
  def main(args: Array[String]): Unit = {
    // 基本的 try-catch
    def divide(x: Int, y: Int): Double = {
      try {
        x.toDouble / y
      } catch {
        case _: ArithmeticException => 
          println("除零错误")
          0.0
        case e: Exception => 
          println(s"其他错误: ${e.getMessage}")
          0.0
      }
    }
    
    println(s"10 / 2 = ${divide(10, 2)}")
    println(s"10 / 0 = ${divide(10, 0)}")
    
    // 带 finally 的异常处理
    def readFileWithFinally(filename: String): String = {
      var reader: BufferedReader = null
      try {
        reader = new BufferedReader(new FileReader(filename))
        reader.readLine()
      } catch {
        case _: IOException => 
          println(s"读取文件 $filename 失败")
          ""
        case e: Exception => 
          println(s"未知错误: ${e.getMessage}")
          ""
      } finally {
        if (reader != null) {
          try {
            reader.close()
          } catch {
            case _: IOException => println("关闭文件失败")
          }
        }
      }
    }
    
    // 多种异常类型的处理
    def parseAndProcess(input: String): Int = {
      try {
        val number = input.toInt
        if (number < 0) throw new IllegalArgumentException("数字不能为负")
        number * 2
      } catch {
        case _: NumberFormatException => 
          println("输入不是有效数字")
          0
        case e: IllegalArgumentException => 
          println(s"参数错误: ${e.getMessage}")
          0
        case e: Exception => 
          println(s"未知错误: ${e.getMessage}")
          0
      }
    }
    
    val inputs = List("10", "-5", "abc", "20")
    inputs.foreach(input => println(s"处理 '$input': ${parseAndProcess(input)}"))
  }
}

异常的抛出

scala
object ThrowingExceptions {
  // 自定义异常
  class InvalidAgeException(message: String) extends Exception(message)
  class InsufficientFundsException(message: String, val balance: Double) extends Exception(message)
  
  case class Person(name: String, age: Int) {
    if (age < 0) throw new InvalidAgeException(s"年龄不能为负数: $age")
    if (age > 150) throw new InvalidAgeException(s"年龄不能超过150: $age")
  }
  
  class BankAccount(private var balance: Double) {
    def withdraw(amount: Double): Double = {
      if (amount <= 0) {
        throw new IllegalArgumentException("取款金额必须大于0")
      }
      if (amount > balance) {
        throw new InsufficientFundsException(s"余额不足,当前余额: $balance", balance)
      }
      balance -= amount
      balance
    }
    
    def getBalance: Double = balance
  }
  
  // 条件抛出异常
  def validateEmail(email: String): String = {
    if (email == null || email.trim.isEmpty) {
      throw new IllegalArgumentException("邮箱不能为空")
    }
    if (!email.contains("@")) {
      throw new IllegalArgumentException("邮箱格式无效")
    }
    email.toLowerCase
  }
  
  def main(args: Array[String]): Unit = {
    // 测试自定义异常
    try {
      val person1 = Person("Alice", 25)
      println(s"创建成功: $person1")
      
      val person2 = Person("Bob", -5)  // 会抛出异常
    } catch {
      case e: InvalidAgeException => 
        println(s"年龄验证失败: ${e.getMessage}")
    }
    
    // 测试银行账户异常
    val account = new BankAccount(1000.0)
    try {
      println(s"取款前余额: ${account.getBalance}")
      account.withdraw(500.0)
      println(s"取款500后余额: ${account.getBalance}")
      account.withdraw(600.0)  // 会抛出异常
    } catch {
      case e: InsufficientFundsException => 
        println(s"取款失败: ${e.getMessage}")
        println(s"当前余额: ${e.balance}")
      case e: IllegalArgumentException => 
        println(s"参数错误: ${e.getMessage}")
    }
    
    // 测试邮箱验证
    val emails = List("user@example.com", "", "invalid-email", null)
    emails.foreach { email =>
      try {
        val validEmail = validateEmail(email)
        println(s"有效邮箱: $validEmail")
      } catch {
        case e: IllegalArgumentException => 
          println(s"邮箱验证失败: ${e.getMessage}")
        case e: NullPointerException => 
          println("邮箱为null")
      }
    }
  }
}

函数式异常处理

Try 类型

scala
import scala.util.{Try, Success, Failure}
import scala.io.Source
import java.net.URL

object TryExceptionHandling {
  // 使用 Try 包装可能失败的操作
  def safeDivide(x: Double, y: Double): Try[Double] = {
    Try(x / y)
  }
  
  def safeParseInt(str: String): Try[Int] = {
    Try(str.toInt)
  }
  
  def safeReadFile(filename: String): Try[String] = {
    Try {
      val source = Source.fromFile(filename)
      try {
        source.mkString
      } finally {
        source.close()
      }
    }
  }
  
  def safeHttpRequest(url: String): Try[String] = {
    Try {
      val source = Source.fromURL(new URL(url))
      try {
        source.mkString
      } finally {
        source.close()
      }
    }
  }
  
  // Try 的链式操作
  def processUserInput(input: String): Try[String] = {
    for {
      number <- safeParseInt(input)
      doubled = number * 2
      result <- Try(s"结果: $doubled")
    } yield result
  }
  
  // 组合多个 Try 操作
  def calculateAverage(numbers: List[String]): Try[Double] = {
    val parsedNumbers = numbers.map(safeParseInt)
    
    // 检查是否所有解析都成功
    val allSuccess = parsedNumbers.forall(_.isSuccess)
    
    if (allSuccess) {
      val values = parsedNumbers.map(_.get)
      Try(values.sum.toDouble / values.length)
    } else {
      Failure(new IllegalArgumentException("包含无效数字"))
    }
  }
  
  def main(args: Array[String]): Unit = {
    // 基本 Try 使用
    val division1 = safeDivide(10.0, 2.0)
    val division2 = safeDivide(10.0, 0.0)
    
    division1 match {
      case Success(result) => println(s"除法成功: $result")
      case Failure(exception) => println(s"除法失败: ${exception.getMessage}")
    }
    
    division2 match {
      case Success(result) => println(s"除法成功: $result")
      case Failure(exception) => println(s"除法失败: ${exception.getMessage}")
    }
    
    // Try 的函数式操作
    val numbers = List("10", "20", "abc", "30")
    numbers.foreach { numStr =>
      val result = safeParseInt(numStr)
        .map(_ * 2)
        .map(n => s"翻倍结果: $n")
        .recover {
          case _: NumberFormatException => s"'$numStr' 不是有效数字"
        }
      
      println(result.getOrElse("处理失败"))
    }
    
    // 链式操作
    val inputs = List("5", "abc", "10")
    inputs.foreach { input =>
      processUserInput(input) match {
        case Success(result) => println(result)
        case Failure(exception) => println(s"处理失败: ${exception.getMessage}")
      }
    }
    
    // 计算平均值
    val numberLists = List(
      List("1", "2", "3", "4", "5"),
      List("10", "20", "abc"),
      List("100", "200", "300")
    )
    
    numberLists.foreach { numbers =>
      calculateAverage(numbers) match {
        case Success(avg) => println(s"平均值: $avg")
        case Failure(exception) => println(s"计算失败: ${exception.getMessage}")
      }
    }
  }
}

Option 与异常处理

scala
object OptionExceptionHandling {
  // 将异常转换为 Option
  def safeGet[T](list: List[T], index: Int): Option[T] = {
    try {
      Some(list(index))
    } catch {
      case _: IndexOutOfBoundsException => None
    }
  }
  
  def safeDivideOption(x: Double, y: Double): Option[Double] = {
    if (y == 0) None else Some(x / y)
  }
  
  def safeParseIntOption(str: String): Option[Int] = {
    try {
      Some(str.toInt)
    } catch {
      case _: NumberFormatException => None
    }
  }
  
  // 使用 Option 进行安全的链式操作
  def processChain(input: String): Option[String] = {
    for {
      number <- safeParseIntOption(input)
      doubled <- Some(number * 2)
      result <- if (doubled > 0) Some(s"正数结果: $doubled") else None
    } yield result
  }
  
  // 组合多个 Option 操作
  def combineOptions(opt1: Option[Int], opt2: Option[Int]): Option[Int] = {
    for {
      a <- opt1
      b <- opt2
    } yield a + b
  }
  
  // 从 Try 转换为 Option
  def tryToOption[T](t: Try[T]): Option[T] = t.toOption
  
  def main(args: Array[String]): Unit = {
    val list = List(1, 2, 3, 4, 5)
    
    // 安全访问列表元素
    println(s"索引 2: ${safeGet(list, 2)}")
    println(s"索引 10: ${safeGet(list, 10)}")
    
    // 安全除法
    println(s"10 / 2: ${safeDivideOption(10, 2)}")
    println(s"10 / 0: ${safeDivideOption(10, 0)}")
    
    // 链式操作
    val inputs = List("5", "-3", "abc", "10")
    inputs.foreach { input =>
      processChain(input) match {
        case Some(result) => println(result)
        case None => println(s"处理 '$input' 失败")
      }
    }
    
    // 组合操作
    val combinations = List(
      (Some(1), Some(2)),
      (Some(3), None),
      (None, Some(4)),
      (Some(5), Some(6))
    )
    
    combinations.foreach { case (opt1, opt2) =>
      combineOptions(opt1, opt2) match {
        case Some(sum) => println(s"$opt1 + $opt2 = $sum")
        case None => println(s"无法计算 $opt1 + $opt2")
      }
    }
    
    // Try 转 Option
    val tryResults = List(
      Try("hello".toInt),
      Try("123".toInt),
      Try(10 / 0)
    )
    
    tryResults.foreach { t =>
      val opt = tryToOption(t)
      println(s"Try 转 Option: $opt")
    }
  }
}
```## 
Either 类型错误处理

### Either 基础使用

```scala
object EitherErrorHandling {
  // 使用 Either 进行错误处理
  def safeDivideEither(x: Double, y: Double): Either[String, Double] = {
    if (y == 0) Left("除数不能为零")
    else Right(x / y)
  }
  
  def validateAge(age: Int): Either[String, Int] = {
    if (age < 0) Left("年龄不能为负数")
    else if (age > 150) Left("年龄不能超过150")
    else Right(age)
  }
  
  def validateEmail(email: String): Either[String, String] = {
    if (email == null || email.trim.isEmpty) Left("邮箱不能为空")
    else if (!email.contains("@")) Left("邮箱格式无效")
    else Right(email.toLowerCase)
  }
  
  // 组合多个验证
  case class User(name: String, age: Int, email: String)
  
  def createUser(name: String, age: Int, email: String): Either[List[String], User] = {
    val nameValidation = if (name.trim.nonEmpty) Right(name) else Left("姓名不能为空")
    val ageValidation = validateAge(age)
    val emailValidation = validateEmail(email)
    
    (nameValidation, ageValidation, emailValidation) match {
      case (Right(n), Right(a), Right(e)) => Right(User(n, a, e))
      case _ =>
        val errors = List(nameValidation, ageValidation, emailValidation)
          .collect { case Left(error) => error }
        Left(errors)
    }
  }
  
  // Either 的函数式操作
  def processNumber(input: String): Either[String, Int] = {
    try {
      val number = input.toInt
      if (number > 0) Right(number * 2)
      else Left("数字必须为正数")
    } catch {
      case _: NumberFormatException => Left(s"'$input' 不是有效数字")
    }
  }
  
  // 链式操作
  def calculateSquareRoot(input: String): Either[String, Double] = {
    for {
      number <- processNumber(input).map(_.toDouble)
      sqrt <- if (number >= 0) Right(math.sqrt(number)) else Left("不能计算负数的平方根")
    } yield sqrt
  }
  
  def main(args: Array[String]): Unit = {
    // 基本 Either 使用
    val divisions = List((10.0, 2.0), (10.0, 0.0), (15.0, 3.0))
    divisions.foreach { case (x, y) =>
      safeDivideEither(x, y) match {
        case Right(result) => println(s"$x / $y = $result")
        case Left(error) => println(s"除法错误: $error")
      }
    }
    
    // 用户创建验证
    val userInputs = List(
      ("Alice", 25, "alice@example.com"),
      ("", 30, "bob@example.com"),
      ("Charlie", -5, "invalid-email"),
      ("Diana", 200, "")
    )
    
    userInputs.foreach { case (name, age, email) =>
      createUser(name, age, email) match {
        case Right(user) => println(s"用户创建成功: $user")
        case Left(errors) => println(s"用户创建失败: ${errors.mkString(", ")}")
      }
    }
    
    // 链式操作
    val inputs = List("4", "16", "-9", "abc", "0")
    inputs.foreach { input =>
      calculateSquareRoot(input) match {
        case Right(result) => println(s"sqrt($input) = $result")
        case Left(error) => println(s"计算失败: $error")
      }
    }
    
    // Either 的 map 和 flatMap
    val numberProcessing = processNumber("5")
      .map(_ + 10)
      .map(n => s"最终结果: $n")
    
    println(s"数字处理结果: $numberProcessing")
  }
}

资源管理

自动资源管理

scala
import scala.util.{Try, Using}
import java.io.{FileWriter, BufferedWriter, FileReader, BufferedReader}

object ResourceManagement {
  // 传统的资源管理(容易出错)
  def writeFileTraditional(filename: String, content: String): Try[Unit] = {
    Try {
      var writer: BufferedWriter = null
      try {
        writer = new BufferedWriter(new FileWriter(filename))
        writer.write(content)
      } finally {
        if (writer != null) {
          writer.close()
        }
      }
    }
  }
  
  // 使用 Using 进行自动资源管理(Scala 2.13+)
  def writeFileUsing(filename: String, content: String): Try[Unit] = {
    Using(new BufferedWriter(new FileWriter(filename))) { writer =>
      writer.write(content)
    }
  }
  
  def readFileUsing(filename: String): Try[String] = {
    Using(new BufferedReader(new FileReader(filename))) { reader =>
      Iterator.continually(reader.readLine())
        .takeWhile(_ != null)
        .mkString("\n")
    }
  }
  
  // 多个资源的管理
  def copyFile(source: String, target: String): Try[Unit] = {
    Using.Manager { use =>
      val reader = use(new BufferedReader(new FileReader(source)))
      val writer = use(new BufferedWriter(new FileWriter(target)))
      
      Iterator.continually(reader.readLine())
        .takeWhile(_ != null)
        .foreach(line => writer.write(line + "\n"))
    }
  }
  
  // 自定义资源管理
  class DatabaseConnection {
    println("数据库连接已建立")
    
    def query(sql: String): String = {
      s"执行查询: $sql"
    }
    
    def close(): Unit = {
      println("数据库连接已关闭")
    }
  }
  
  // 为自定义资源实现 AutoCloseable
  class ManagedDatabaseConnection extends DatabaseConnection with AutoCloseable
  
  def withDatabase[T](operation: DatabaseConnection => T): Try[T] = {
    Using(new ManagedDatabaseConnection())(operation)
  }
  
  // 手动资源管理模式
  def withResource[R <: AutoCloseable, T](resource: => R)(operation: R => T): Try[T] = {
    Try {
      val r = resource
      try {
        operation(r)
      } finally {
        r.close()
      }
    }
  }
  
  def main(args: Array[String]): Unit = {
    val testFile = "test.txt"
    val copyFile = "copy.txt"
    val content = "Hello, World!\nThis is a test file.\nScala resource management."
    
    // 写入文件
    writeFileUsing(testFile, content) match {
      case scala.util.Success(_) => println("文件写入成功")
      case scala.util.Failure(exception) => println(s"文件写入失败: ${exception.getMessage}")
    }
    
    // 读取文件
    readFileUsing(testFile) match {
      case scala.util.Success(fileContent) => 
        println("文件内容:")
        println(fileContent)
      case scala.util.Failure(exception) => 
        println(s"文件读取失败: ${exception.getMessage}")
    }
    
    // 复制文件
    copyFile(testFile, copyFile) match {
      case scala.util.Success(_) => println("文件复制成功")
      case scala.util.Failure(exception) => println(s"文件复制失败: ${exception.getMessage}")
    }
    
    // 数据库操作
    withDatabase { db =>
      val result1 = db.query("SELECT * FROM users")
      val result2 = db.query("SELECT * FROM orders")
      List(result1, result2)
    } match {
      case scala.util.Success(results) => 
        println("数据库查询结果:")
        results.foreach(println)
      case scala.util.Failure(exception) => 
        println(s"数据库操作失败: ${exception.getMessage}")
    }
  }
}

异常处理模式

错误累积模式

scala
object ErrorAccumulation {
  // 验证结果类型
  sealed trait ValidationResult[+A]
  case class Valid[A](value: A) extends ValidationResult[A]
  case class Invalid(errors: List[String]) extends ValidationResult[Nothing]
  
  // 验证器类型
  type Validator[A] = A => ValidationResult[A]
  
  // 组合验证器
  implicit class ValidationOps[A](validation: ValidationResult[A]) {
    def combine[B, C](other: ValidationResult[B])(f: (A, B) => C): ValidationResult[C] = {
      (validation, other) match {
        case (Valid(a), Valid(b)) => Valid(f(a, b))
        case (Invalid(errors1), Invalid(errors2)) => Invalid(errors1 ++ errors2)
        case (Invalid(errors), _) => Invalid(errors)
        case (_, Invalid(errors)) => Invalid(errors)
      }
    }
    
    def map[B](f: A => B): ValidationResult[B] = validation match {
      case Valid(value) => Valid(f(value))
      case Invalid(errors) => Invalid(errors)
    }
    
    def flatMap[B](f: A => ValidationResult[B]): ValidationResult[B] = validation match {
      case Valid(value) => f(value)
      case Invalid(errors) => Invalid(errors)
    }
  }
  
  // 具体验证器
  def validateName(name: String): ValidationResult[String] = {
    if (name.trim.isEmpty) Invalid(List("姓名不能为空"))
    else if (name.length < 2) Invalid(List("姓名至少2个字符"))
    else Valid(name.trim)
  }
  
  def validateAge(age: Int): ValidationResult[Int] = {
    val errors = List(
      if (age < 0) Some("年龄不能为负数") else None,
      if (age > 150) Some("年龄不能超过150") else None
    ).flatten
    
    if (errors.nonEmpty) Invalid(errors) else Valid(age)
  }
  
  def validateEmail(email: String): ValidationResult[String] = {
    val errors = List(
      if (email.trim.isEmpty) Some("邮箱不能为空") else None,
      if (!email.contains("@")) Some("邮箱必须包含@符号") else None,
      if (!email.contains(".")) Some("邮箱必须包含域名") else None
    ).flatten
    
    if (errors.nonEmpty) Invalid(errors) else Valid(email.toLowerCase)
  }
  
  case class Person(name: String, age: Int, email: String)
  
  def validatePerson(name: String, age: Int, email: String): ValidationResult[Person] = {
    val nameResult = validateName(name)
    val ageResult = validateAge(age)
    val emailResult = validateEmail(email)
    
    // 累积所有错误
    (nameResult, ageResult, emailResult) match {
      case (Valid(n), Valid(a), Valid(e)) => Valid(Person(n, a, e))
      case _ =>
        val allErrors = List(nameResult, ageResult, emailResult)
          .collect { case Invalid(errors) => errors }
          .flatten
        Invalid(allErrors)
    }
  }
  
  def main(args: Array[String]): Unit = {
    val testCases = List(
      ("Alice", 25, "alice@example.com"),
      ("", -5, "invalid-email"),
      ("B", 200, ""),
      ("Charlie", 30, "charlie@test.com")
    )
    
    testCases.foreach { case (name, age, email) =>
      validatePerson(name, age, email) match {
        case Valid(person) => 
          println(s"✓ 验证成功: $person")
        case Invalid(errors) => 
          println(s"✗ 验证失败:")
          errors.foreach(error => println(s"  - $error"))
      }
      println()
    }
  }
}

重试模式

scala
import scala.util.{Try, Success, Failure}
import scala.concurrent.duration._

object RetryPattern {
  // 简单重试
  def retry[T](operation: => T, maxAttempts: Int): Try[T] = {
    def attempt(attemptsLeft: Int): Try[T] = {
      Try(operation) match {
        case success @ Success(_) => success
        case Failure(exception) if attemptsLeft > 1 =>
          println(s"操作失败,剩余重试次数: ${attemptsLeft - 1}")
          Thread.sleep(100) // 简单延迟
          attempt(attemptsLeft - 1)
        case failure => failure
      }
    }
    
    attempt(maxAttempts)
  }
  
  // 带指数退避的重试
  def retryWithBackoff[T](
    operation: => T, 
    maxAttempts: Int, 
    initialDelay: Duration = 100.millis,
    backoffFactor: Double = 2.0
  ): Try[T] = {
    def attempt(attemptsLeft: Int, delay: Duration): Try[T] = {
      Try(operation) match {
        case success @ Success(_) => success
        case Failure(exception) if attemptsLeft > 1 =>
          println(s"操作失败: ${exception.getMessage}")
          println(s"等待 ${delay.toMillis}ms 后重试,剩余次数: ${attemptsLeft - 1}")
          Thread.sleep(delay.toMillis)
          attempt(attemptsLeft - 1, Duration.fromNanos((delay.toNanos * backoffFactor).toLong))
        case failure => failure
      }
    }
    
    attempt(maxAttempts, initialDelay)
  }
  
  // 条件重试
  def retryIf[T](
    operation: => T, 
    maxAttempts: Int,
    shouldRetry: Throwable => Boolean
  ): Try[T] = {
    def attempt(attemptsLeft: Int): Try[T] = {
      Try(operation) match {
        case success @ Success(_) => success
        case Failure(exception) if attemptsLeft > 1 && shouldRetry(exception) =>
          println(s"可重试的错误: ${exception.getMessage}")
          Thread.sleep(100)
          attempt(attemptsLeft - 1)
        case failure => failure
      }
    }
    
    attempt(maxAttempts)
  }
  
  // 模拟不稳定的操作
  class UnstableService {
    private var callCount = 0
    
    def unreliableOperation(): String = {
      callCount += 1
      if (callCount < 3) {
        throw new RuntimeException(s"服务暂时不可用 (调用次数: $callCount)")
      }
      s"操作成功 (调用次数: $callCount)"
    }
    
    def networkOperation(): String = {
      if (scala.util.Random.nextDouble() < 0.7) {
        throw new java.net.ConnectException("网络连接失败")
      }
      "网络请求成功"
    }
    
    def databaseOperation(): String = {
      if (scala.util.Random.nextDouble() < 0.5) {
        throw new java.sql.SQLException("数据库连接超时")
      }
      "数据库操作成功"
    }
  }
  
  def main(args: Array[String]): Unit = {
    val service = new UnstableService()
    
    // 简单重试
    println("=== 简单重试 ===")
    retry(service.unreliableOperation(), 5) match {
      case Success(result) => println(s"成功: $result")
      case Failure(exception) => println(s"最终失败: ${exception.getMessage}")
    }
    
    // 带退避的重试
    println("\n=== 指数退避重试 ===")
    retryWithBackoff(service.networkOperation(), 3) match {
      case Success(result) => println(s"成功: $result")
      case Failure(exception) => println(s"最终失败: ${exception.getMessage}")
    }
    
    // 条件重试
    println("\n=== 条件重试 ===")
    val shouldRetryNetwork = (ex: Throwable) => ex.isInstanceOf[java.net.ConnectException]
    
    retryIf(service.databaseOperation(), 3, shouldRetryNetwork) match {
      case Success(result) => println(s"成功: $result")
      case Failure(exception) => println(s"最终失败: ${exception.getMessage}")
    }
  }
}

最佳实践

异常处理指南

scala
object ExceptionBestPractices {
  // 1. 使用具体的异常类型
  class UserNotFoundException(userId: String) extends Exception(s"用户未找到: $userId")
  class InvalidPasswordException(message: String) extends Exception(message)
  
  // 2. 提供有意义的错误信息
  def authenticateUser(username: String, password: String): Either[String, String] = {
    if (username.isEmpty) {
      Left("用户名不能为空")
    } else if (password.length < 8) {
      Left("密码长度至少8位")
    } else if (!password.exists(_.isDigit)) {
      Left("密码必须包含数字")
    } else {
      Right(s"用户 $username 认证成功")
    }
  }
  
  // 3. 使用 Try 处理可能失败的操作
  def safeOperation[T](operation: => T): Try[T] = Try(operation)
  
  // 4. 优雅的错误恢复
  def withFallback[T](primary: => T, fallback: => T): T = {
    try {
      primary
    } catch {
      case _: Exception => fallback
    }
  }
  
  // 5. 记录异常信息
  def logAndHandle[T](operation: => T, operationName: String): Option[T] = {
    try {
      Some(operation)
    } catch {
      case ex: Exception =>
        println(s"操作 '$operationName' 失败: ${ex.getMessage}")
        // 在实际应用中,这里应该使用日志框架
        None
    }
  }
  
  // 6. 避免吞噬异常
  def processWithLogging[T](items: List[T])(processor: T => Unit): List[T] = {
    val failed = scala.collection.mutable.ListBuffer[T]()
    
    items.foreach { item =>
      try {
        processor(item)
      } catch {
        case ex: Exception =>
          println(s"处理项目失败: $item, 错误: ${ex.getMessage}")
          failed += item
      }
    }
    
    failed.toList
  }
  
  def main(args: Array[String]): Unit = {
    // 演示最佳实践
    
    // 1. 具体异常类型的使用
    val authResults = List(
      ("alice", "password123"),
      ("", "short"),
      ("bob", "validpassword1")
    )
    
    authResults.foreach { case (username, password) =>
      authenticateUser(username, password) match {
        case Right(message) => println(s"✓ $message")
        case Left(error) => println(s"✗ 认证失败: $error")
      }
    }
    
    // 2. 使用 fallback
    val primaryValue = withFallback(
      throw new RuntimeException("主要操作失败"),
      "备用值"
    )
    println(s"Fallback 结果: $primaryValue")
    
    // 3. 记录和处理
    val result = logAndHandle(
      10 / 0,
      "除法运算"
    )
    println(s"记录处理结果: $result")
    
    // 4. 批量处理错误
    val numbers = List("1", "2", "abc", "4", "def")
    val failedItems = processWithLogging(numbers) { numStr =>
      val num = numStr.toInt
      println(s"处理数字: $num")
    }
    println(s"处理失败的项目: $failedItems")
  }
}

总结

Scala 提供了多种异常处理机制:

  1. 传统异常处理

    • try-catch-finally
    • 抛出自定义异常
    • 适合与Java互操作
  2. 函数式错误处理

    • Try 类型:包装可能失败的操作
    • Option 类型:处理可能为空的值
    • Either 类型:明确的错误信息
  3. 资源管理

    • Using 类型:自动资源管理
    • 自定义资源管理模式
    • 确保资源正确释放
  4. 高级模式

    • 错误累积:收集所有验证错误
    • 重试模式:处理临时性失败
    • 优雅降级:提供备用方案

选择合适的异常处理方式取决于具体场景,函数式方法通常更安全和可组合。

本站内容仅供学习和研究使用。