1. 异常基本分类
1.1 Exception vs Error
在 Java 中,Throwable、Error、Exception、RuntimeException 是常见异常的基类。
Exception 和 Error 都继承自 Throwable 类。
try { // 可以在此处抛出异常 ... } catch (Throwable e) { // 可以在此处捕获并处理异常 ... }
- Exception 被用于表示程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应处理。
- Error 被用于表示在程序正常运行中,不大可能出现的情况。绝大部分的 Error 都会导致程序处于非正常、不可恢复的状态。这类异常一般不便于也不需要捕获。
1.2 Checked Exception vs Unchecked Exception
Java异常分为受检(checked)异常和非受检(unchecked)异常。
对于Checked Exception,必须在代码里显式地捕获处理。
对于Unchecked Exception,可以根据实际业务需要决定是否在代码中显式地捕获处理。
根据 Java文档的定义,任何既不是 Error(或其子类),也不是 RuntimeException(或其子类)的异常,都是 Checked Exception。
"For the purposes of compile-time checking of exceptions, Throwable and any subclass of Throwable that is not also a subclass of either RuntimeException or Error are regarded as checked exceptions."
1.3 NoClassDefFoundError vs ClassNotFoundException
NoClassDefFoundError 属于 Error。产生原因是在编译时该类是存在的,但在运行时找不到该类。很可能是程序打包时漏掉了这个类。
ClassNotFoundException 属于 Exception。主要是通过Java的反射机制加载类时产生(Class.forName 方法)。很可能是类名拼写错误,或目标类不在类路径下。
2. 常见使用方式
- try-with-resource:该方式可以简化对需释放(关闭)资源的处理,避免异常导致资源无法释放的情况。
- multiple catch:该方式可在同一个代块中处理多种类型的异常,以优化代码布局。
例:
try (BufferedReader br = new BufferedReader(...); BufferedWriter bw = new BufferedWriter(...)) { // try-with-resource ... } catch (ExceptionA | ExceptionB e) { // multiple catch ... }
3. 一般使用原则
3.1 捕获特定异常,而不是通用异常(如,Exception)
显式地捕获特定异常是对业务的更精确实现,也有助于日后的维护重构(代码也是文档)。
对通用异常的捕获可能会导致误捕获意料之外的异常,但同时又缺乏对这些不速之客恰当的处理。
3.2 不要生吞异常
生吞异常是指捕获异常后未作任何有效的处理,而是直接忽略了异常。
生吞异常很可能导致程序出异常时诊断十分困难。
即使已经假设异常分支不可能发生,或目标异常被忽略也无所谓,也最好有相应的日志纪录。
如果实在不知道如何处理,可以直接再抛出,或构建新的异常(保留原异常信息)再抛出,由上层调用代码处理该异常。
因为上层代码的业务逻辑可能更明晰,往往有更合理的处理方案。
3.3 不要调用 printStackTrace() 方法来纪录异常日志
该方法是将异常错误信息输出到 标准出错流 中。
在真实的系统环境中,情况很可能复杂到无法快速判断出错信息到底输出到了哪。也就是说 标准出错流 可能被重定向到了一个你不知道的地方。
正确的做法是将异常信息输出到日志系统中。
3.4 尽早抛异常
尽早抛出异常可以更清晰地反映问题。如果推迟到由更深层的方法抛出异常,所得堆栈信息会更令人费解。
void func1(String fileName) { ... InputStream in = new FileInputStream(fileName); ... } void func2(String fileName) { Objects.requireNonNull(fileName); // 尽早抛出异常 ... InputStream in = new FileInputStream(fileName); ... }
3.5 谨慎自定义受检异常(Checked Exception)
Checked Exception的定义初衷应该是指望方法的调用者在捕获异常后从异常中恢复。
但在实际应用中,这种情况很少见,反而是Checked Exception导致代码可读性更差,对 Lambda 或 Stream 代码不友好。
实际情况已大大偏离了Checked Exception的设计目的。
3.6 不要在诊断信息中包含敏感信息
设计自定义异常类时,充足的诊断信息可以帮助更快得理解问题。但是如果包含了敏感信息,可能就是潜在的安全问题。
如,用户信息一般就是不适合输出到日志中的,机器名、IP、端口等也属于敏感信息。
3.7 仅捕获必要的代码段
try-catch 代码段会产生额外的性能开销,往往影响JVM对代码的优化。
3.8 不要用异常控制代码流程
传统的 if-else、switch 流程控制方式比异常控制方式更高效。
Java每实例化一个 Exception 都会对当时的栈进行快照,开销比较重。
不过在实际使用时需要根据具体情况做取舍。在一些抽象框架性的代码中,用异常控制流程也是不错的选择。
相关推荐
计算机后端-Java-Java核心基础-第17章 异常处理 06. 异常概述.avi
计算机后端-Java-Java核心基础-第17章 异常处理 17. 如何自定义异常.avi
计算机后端-Java-Java核心基础-第17章 异常处理 07. 异常的分类.avi
计算机后端-Java-Java核心基础-第17章 异常处理 08. 常见异常的举例.avi
计算机后端-Java-Java核心基础-第17章 异常处理 20. 异常处理章节总结.avi
计算机后端-Java-Java核心基础-第17章 异常处理 13. 处理异常:throws方式.avi
计算机后端-Java-Java核心基础-第17章 异常处理 16. 手动抛出异常对象.avi
计算机后端-Java-Java核心基础-第17章 异常处理 18. 异常处理练习:基本使用.avi
计算机后端-Java-Java核心基础-第17章 异常处理 19. 异常处理练习:综合练习.avi
计算机后端-Java-Java核心基础-第17章 异常处理 03. 复习:接口.avi
计算机后端-Java-Java核心基础-第17章 异常处理 11. finally的使用.avi
计算机后端-Java-Java核心基础-第17章 异常处理 01. 每天一考.avi
《Java核心技术-基础知识(第8版中文版)》是一本深度探讨Java编程语言核心概念和技术的权威指南。这本书主要涵盖了Java编程的基础要素,是初学者和有经验的开发者提升技能的重要资源。书中详细讲解了Java语言的核心...
计算机后端-Java-Java核心基础-第17章 异常处理 12. 编译时异常和运行时异常的不同处
计算机后端-Java-Java核心基础-第17章 异常处理 14. 重写方法异常抛出的规则.avi
计算机后端-Java-Java核心基础-第17章 异常处理 02. 复习:抽象类.avi
计算机后端-Java-Java核心基础-第17章 异常处理 04. 复习:内部类.avi
计算机后端-Java-Java核心基础-第17章 异常处理 15. 开发中如何选择哪种方式处理异常.avi
计算机后端-Java-Java核心基础-第17章 异常处理 05. 局部内部类使用的一个注意点.avi
这本书涵盖了从Java语言的基本语法、数据类型到类和对象,再到异常处理、集合框架等核心概念,旨在为初学者提供一个全面且深入的学习路径。以下是根据这个主题提炼出的一些关键知识点: 1. **Java简介**:Java是一...