文章目录

Groovy 异常处理:try-catch-finally

发布于 2026-04-03 03:27:59 · 浏览 7 次 · 评论 0 条

Groovy 异常处理:try-catch-finally

在 Groovy 中编写健壮的程序,必须正确处理运行时可能出现的错误。Groovy 继承了 Java 的异常处理机制,并在此基础上做了简化和增强。使用 try-catch-finally 结构,你可以捕获异常、执行清理操作,并确保程序不会因未处理的错误而崩溃。


理解异常的基本概念

异常 是程序运行过程中发生的意外事件,比如文件不存在、网络中断或除零错误。Groovy 将异常分为两类:

  • 受检异常(Checked Exception):编译器强制要求处理的异常(如 IOException),但在 Groovy 中通常可忽略,因为 Groovy 默认将所有异常视为非受检。
  • 非受检异常(Unchecked Exception):继承自 RuntimeException 的异常(如 NullPointerException),不需要显式声明或捕获,但建议处理以提升稳定性。

Groovy 允许你像写脚本一样省略异常声明,但仍可通过 try-catch-finally 主动控制错误流。


编写基础的 try-catch 块

包裹可能出错的代码try 块中,并用 catch 捕获特定类型的异常。

  1. 创建 一个包含潜在风险操作的代码块,例如读取文件:

    try {
        new File("nonexistent.txt").text
    } catch (FileNotFoundException e) {
        println "文件没找到:${e.message}"
       }
       ```
    
    2. **捕获多种异常** 可以使用多个 `catch` 子句,按从具体到一般的顺序排列:
       ```groovy
       try {
           // 可能抛出多种异常的操作
           def num = Integer.parseInt("abc")
       } catch (NumberFormatException e) {
           println "数字格式错误"
       } catch (Exception e) {
           println "其他错误:${e.class.simpleName}"
    }
  2. 省略异常类型(Groovy 特有):如果你只关心是否出错而不关心具体类型,可直接写 catch (e)

    try {
        throw new RuntimeException("测试异常")
    } catch (e) {
        println "捕获到异常:${e.message}"
       }
       ```
    
    ---
    
    ## 使用 finally 执行清理操作
    
    无论是否发生异常,`finally` 块中的代码**总会执行**,适合用于释放资源(如关闭文件、数据库连接)。
    
    1. **打开文件后确保关闭**:
       ```groovy
       def file = null
       try {
           file = new File("data.txt")
           println file.text
       } catch (IOException e) {
           println "读取失败:${e.message}"
    } finally {
        if (file?.exists()) {
            // 虽然 Groovy 的 File 不需要显式 close,但对流类资源很重要
            println "清理完成"
        }
    }
  3. 结合资源自动管理(推荐替代方案):Groovy 支持 withCloseable 方法,可自动关闭实现了 Closeable 接口的对象:

    new FileInputStream("input.txt").withCloseable { stream ->
        // 使用 stream 处理数据
        println stream.available()
    } // 自动调用 close()

高级技巧:异常传播与重新抛出

有时你需要捕获异常做日志记录,再让异常继续向上层传递。

  1. 记录日志后重新抛出
    
    try {
        riskyOperation()
    } catch (Exception e) {
        println "记录错误日志:${e.message}"
           throw e // 重新抛出原异常
       }
       ```
    
    2. **包装为自定义异常** 提供更清晰的上下文:
       ```groovy
       try {
           connectToDatabase()
       } catch (SQLException e) {
           throw new RuntimeException("数据库连接失败,请检查配置", e)
       }
       ```
    
    ---
    
    ## 常见陷阱与最佳实践
    
    避免以下错误可大幅提升代码可靠性:
    
    | 问题 | 正确做法 |
    | :--- | :--- |
    | 空 `catch` 块(吞掉异常) | **至少记录日志**,如 `println e` 或使用日志框架 |
    | 捕获过于宽泛的 `Exception` | **优先捕获具体异常类型**,避免掩盖真正的问题 |
    | 在 `finally` 中抛出新异常 | **避免在 `finally` 中抛异常**,否则会覆盖原始异常 |
    
    1. **不要忽略异常**:
       ```groovy
       // 错误示例
       try {
           doSomething()
       } catch (Exception ignored) {} // 危险!问题被隐藏
    
       // 正确做法
       try {
           doSomething()
       } catch (Exception e) {
           log.error("操作失败", e)
       }
       ```
    
    2. **利用 Groovy 的安全操作符减少异常**:使用 `?.` 和 `?:` 可避免 `NullPointerException`:
       ```groovy
       def user = getUser()
       def name = user?.name ?: "匿名用户" // 安全访问属性
       ```
    
    ---
    
    ## 实战:完整文件读取示例
    
    下面是一个兼顾健壮性与简洁性的文件读取函数:
    
    ```groovy
    def readFileSafely(String path) {
        def content = ""
        try {
            content = new File(path).text
            println "成功读取 ${path},共 ${content.size()} 字符"
        } catch (FileNotFoundException e) {
            println "❌ 文件不存在:${path}"
     } catch (SecurityException e) {
         println "🔒 权限不足,无法读取 ${path}"
        } catch (IOException e) {
            println "⚙️ 读取时发生 I/O 错误:${e.message}"
     } finally {
         println "—— 文件操作结束 ——"
     }
     return content
    }

// 调用示例
readFileSafely("example.txt")

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文