- java.lang.Throwable是Java中所有异常(Exception)和错误(Error)的基类。
java.lang.Object
└── java.lang.Throwable
├── java.lang.Error
└── java.lang.Exception
- JVM运行时仅会抛出Throwable及其子类。
- 编译检查机制:
- Checked Exception:
- 除了RuntimeException和Error外的Throwable子类都是为受检异常(Checked exception)
- 调用者必须显示声明/捕获,在方法中用throws声明或者使用
try-catch捕获。例如:IOException,ClassNotFoundException,SQLException
- Unchecked Exception:
- 编译阶段不强制检测和处理。包含RuntimeException及子类,Error及子类。
- Checked Exception:
- 在日志中搜索Crash,可以搜索:FATAL EXCEPTION
public void classDemo() {
try {
Class.forName("com.example.NonExistentClass");
} catch (ClassNotFoundException e) {
System.out.println("Class not found: " + e.getMessage());
}
}
public void sqlDemo() {
try (Connection conn = DriverManager.getConnection(url, user, password)) {
System.out.println("Connected to the database.");
} catch (SQLException e) {
System.out.println("Database connection failed: " + e.getMessage());
}
}
对于Kotlin
fun fileDemo() {
try {
BufferedReader(FileReader("file.txt")).use { br ->
println(br.readLine())
}
} catch (e: IOException) {
e.printStackTrace()
}
}
fun sqlDemo() {
val url = "jdbc:mysql://localhost:3306/testdb"
val user = "root"
val password = "password"
try {
// 不需要显式关闭连接conn.close()了
DriverManager.getConnection(url, user, password).use { conn ->
println("Connection established: $conn")
}
} catch (e: SQLException) {
println("Database connection error: ${e.message}")
}
}
最佳实践
- 避免捕获Throwable,Error
捕获Error会导致掩盖OOM等严重故障,不利于问题定位。
- 链式抛出
自定义异常的时候,将底层异常作为cause传入,上层捕获者能够获得完整上下文
- 日志与上报
捕获后打印/上报 statckTrace, message, cause帮助定位,注意不要直接打印,而是用内部工具,避免数据泄漏。
- 设计自定义异常
继承自RuntimeException或特定业务基类;提供多种构造器,以便支持message、cause、实际的业务数据
如果期望自定义异常为checked exception,则可继承自Exception类;如果期望自定义异常为uncheked exception,则可继承自RuntimeException类。通常业务中定义的异常都是unchecked excpetion,因为异常是根据特定的业务逻辑导致的,通常无法在编译期捕获处理。
// 自定义checked exception
class CustomCheckedException(message: String) : Exception(message) {
// 可以添加更多的属性和方法
}
// 自定义unchecked exception
class CustomUncheckedException(message: String) : RuntimeException(message) {
// 可以添加更多的属性和方法
}
-
早抛出,晚捕获
- Early Throw, Late catch原则:尽早抛出异常,并延迟捕获异常能够有效处理的地方。早抛出可以避免将错误传播到更复杂的地方。
- 如果过早的捕获,而不做记录,抛出,则称为“错误吞噬”,可能导致重要问题被忽略。
- 晚捕获可以收集足够的上下文环境信息。
- 晚捕获可以在高层结构集中处理异常,避免多处捕获导致代码混乱。
- Early Throw, Late catch原则:尽早抛出异常,并延迟捕获异常能够有效处理的地方。早抛出可以避免将错误传播到更复杂的地方。
-
资源管理
始终使用try-with-resources管理可关闭资源。
java.lang.RuntimeException的各种构造方法定义