Java 实例 – Finally的用法(手把手讲解)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新开坑项目:《Spring AI 项目实战》 正在持续爆肝中,基于 Spring AI + Spring Boot 3.x + JDK 21..., 点击查看 ;
  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

前言

在 Java 程序开发中,异常处理是代码健壮性的重要保障。try-catch 块虽然能捕获并处理异常,但若想确保某些关键操作(如资源释放)无论是否发生异常都能执行,就需要借助 finally 子句。本文将通过实例解析 finally 的核心用法、执行逻辑及常见误区,并结合真实开发场景提供解决方案。


一、finally 的基础概念与核心作用

1.1 什么是 finally

finally 是 Java 异常处理机制中的一个关键字,通常与 trycatch 联合使用。其核心作用是 确保某段代码在 try 块执行完毕后,无论是否发生异常、无论通过何种方式退出 try 块,都能被执行

形象比喻
可以将 finally 想象为程序中的“保险机制”。例如,当你在厨房烹饪时,无论是否成功完成一道菜(正常执行),或是中途打翻了锅(发生异常),最后一步都必须关掉燃气灶(释放资源)。

1.2 finally 的典型应用场景

  • 资源释放:如关闭文件流、数据库连接、网络套接字等。
  • 清理操作:如重置临时变量、恢复系统状态。
  • 日志记录:无论程序是否成功,都需要记录关键操作的执行结果。

二、finally 的执行流程与逻辑

2.1 基础语法结构

try {  
    // 可能抛出异常的代码  
} catch (ExceptionType name) {  
    // 异常处理逻辑  
} finally {  
    // 必须执行的代码  
}  

2.2 执行流程的 4 种场景

场景 1:try 内未抛出异常

try {  
    System.out.println("Try block executed normally");  
} finally {  
    System.out.println("Finally block executed");  
}  
// 输出:  
// Try block executed normally  
// Finally block executed  

场景 2:try 内抛出异常,且被 catch 捕获

try {  
    System.out.println("Try block starts");  
    throw new ArithmeticException("Divide by zero");  
} catch (ArithmeticException e) {  
    System.out.println("Catch block handles exception");  
} finally {  
    System.out.println("Finally block executes");  
}  
// 输出:  
// Try block starts  
// Catch block handles exception  
// Finally block executes  

场景 3:try 内抛出未被捕获的异常

try {  
    System.out.println("Try block starts");  
    throw new RuntimeException("Uncaught exception");  
} finally {  
    System.out.println("Finally block executes");  
}  
// 输出:  
// Try block starts  
// Finally block executes  
// 然后程序因未捕获的异常终止  

场景 4:trycatch 内通过 returnbreakcontinue 退出

public static void example() {  
    try {  
        System.out.println("Try block");  
        return; // 提前退出方法  
    } finally {  
        System.out.println("Finally block");  
    }  
}  
// 调用 example() 后的输出:  
// Try block  
// Finally block  

2.3 关键特性总结

  • 不可替代性:即使 try 内通过 returnbreak 或异常直接退出,finally 仍会执行。
  • 优先级顺序:若 trycatch 内有 returnfinally 会在 return 执行后才运行。
  • 异常叠加:如果 finally 内抛出异常,会覆盖原有的异常。

三、finally 的实际应用与代码示例

3.1 资源释放的经典案例:文件操作

FileInputStream fis = null;  
try {  
    fis = new FileInputStream("data.txt");  
    // 读取文件内容  
} catch (FileNotFoundException e) {  
    System.out.println("File not found");  
} finally {  
    if (fis != null) {  
        try {  
            fis.close(); // 关闭资源  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
}  

关键点

  • 即使文件未找到(抛出 FileNotFoundException),finally 中的 close() 仍会执行,确保流对象被关闭。
  • 双重 try-catch 结构是为了避免 close() 本身可能抛出的 IOException

3.2 数据库连接的关闭

Connection conn = null;  
try {  
    conn = DriverManager.getConnection(url, user, password);  
    // 执行 SQL 操作  
} catch (SQLException e) {  
    System.out.println("Connection failed");  
} finally {  
    if (conn != null) {  
        try {  
            conn.close();  
        } catch (SQLException e) {  
            e.printStackTrace();  
        }  
    }  
}  

问题延伸
在 Java 7+ 中,可通过 try-with-resources 自动管理资源,但 finally 在兼容旧代码或复杂逻辑时依然重要。

3.3 日志记录与状态重置

public void processRequest() {  
    try {  
        // 处理业务逻辑  
        recordLog("Processing completed");  
    } catch (Exception e) {  
        recordLog("Error occurred: " + e.getMessage());  
        throw e;  
    } finally {  
        resetTemporaryData(); // 清理临时数据  
    }  
}  

作用
无论请求是否成功,resetTemporaryData() 总会执行,避免内存泄漏。


四、finally 的常见误区与注意事项

4.1 误区 1:在 finally 中使用 return

public int divide(int a, int b) {  
    try {  
        return a / b;  
    } catch (ArithmeticException e) {  
        return 0;  
    } finally {  
        System.out.println("Finally executed");  
        return -1; // ❌ 会导致 try/catch 中的 return 被覆盖  
    }  
}  

后果finally 中的 return 会覆盖 trycatch 的返回值,最终返回 -1
建议:避免在 finally 中使用 returnthrow

4.2 误区 2:finally 不保证 100% 执行

以下情况会导致 finally 被跳过:

  • 系统崩溃(如 JVM 强制退出)。
  • 使用 System.exit() 终止程序。
  • 线程被强制中断(如 Thread.stop())。

4.3 误区 3:忽略 finally 中的异常

public void riskyFinally() {  
    try {  
        // 正常逻辑  
    } finally {  
        // 可能抛出异常的代码(如未检查的 null 指针)  
    }  
}  

风险finally 内的异常会覆盖原有异常,导致业务逻辑难以调试。


五、进阶技巧与最佳实践

5.1 结合 try-with-resources 简化代码

// Java 7+ 的新特性,自动关闭实现了 AutoCloseable 的对象  
try (FileInputStream fis = new FileInputStream("data.txt")) {  
    // 读取操作  
} catch (IOException e) {  
    e.printStackTrace();  
}  
// 不需要显式调用 close(),因为 fis 在 finally 中自动关闭  

5.2 多层 try-catch 的嵌套设计

try {  
    // 外层 try  
    try {  
        // 内层 try  
    } finally {  
        // 内层 finally  
    }  
} catch (Exception e) {  
    // 外层 catch  
} finally {  
    // 外层 finally  
}  

执行顺序:内层 finally 先于外层 finally 执行。

5.3 日志与调试的结合

finally 中添加日志,可辅助排查程序状态:

finally {  
    System.out.println("Operation ended. Resources: " + resourceStatus);  
}  

结论

finally 是 Java 异常处理中不可或缺的“安全网”,它确保关键操作始终执行,避免资源泄漏和状态混乱。通过本文的实例与分析,读者应能掌握 finally 的核心逻辑、应用场景及常见陷阱。在实际开发中,建议结合 try-with-resources 和分层设计,进一步提升代码的健壮性与可维护性。

关键词布局回顾

  • 文章标题直接体现关键词“Java 实例 – Finally的用法”。
  • 在基础概念、执行流程、实际案例等部分,通过代码与场景描述自然融入关键词。
  • 结论部分再次呼应主题,强化核心内容的记忆点。

通过本文的深入解析,希望开发者能灵活运用 finally,写出更可靠、高效的 Java 代码。

最新发布