Java 异常
Java 异常
介绍一下Java 的异常体系?
Java 的异常体系结构呈现出清晰的继承关系,顶层是 Throwable
,其下分为 Error
和 Exception
。
Error 类代表 JVM 层面的严重错误,如内存溢出(OutOfMemoryError
)、栈溢出(StackOverflowError
)等,这类异常通常不可恢复,应用程序无需捕获处理。
Exception 表示程序运行中可以预料并处理的问题。又分为两类:
- 编译时异常(Checked Exception):如
IOException
、SQLException
,强制要求在代码中使用try-catch
或通过throws
显式声明,否则编译报错。这类异常强调显式处理,增强程序的健壮性。 - 运行时异常(Unchecked Exception):如
NullPointerException
、ArrayIndexOutOfBoundsException
,是RuntimeException
及其子类,编译器不会强制处理。它们通常由程序逻辑错误导致,应该通过优化代码逻辑避免。
良好的异常处理机制有助于提升系统稳定性、容错能力与调试效率。掌握异常分类对设计可靠 API 接口及调试生产问题至关重要。
常见的 Exception 有哪些?
在 Java 中,Exception
是程序可处理的异常类型,可进一步分为两类:
1. 运行时异常(RuntimeException 及其子类):
这类异常在编译时不会被强制检查,程序可以选择处理或不处理。常见的有:
NullPointerException
:访问 null 引用IndexOutOfBoundsException
:数组或集合越界ClassCastException
:类型强制转换失败ArithmeticException
:算术运算错误,如除以零
这些异常往往源自程序员的疏忽,应通过单元测试、代码审查和静态检查工具尽量避免。
2. 编译时异常(Checked Exception):
这类异常必须在代码中显式处理,否则编译器报错。典型代表包括:
IOException
:文件读写异常SQLException
:数据库操作异常ClassNotFoundException
:类加载失败
这些异常反映了外部环境的不确定性,必须用健壮的捕获机制包裹,确保程序稳定运行。
了解常见异常类型有助于快速定位错误根因,也利于合理设计 API 抛出策略。
throw 和 throws 的区别?
Java 中的异常处理语法中,throw
和 throws
虽仅差一个字母,但语义完全不同:
throw
是一个操作符,用于在方法体内部抛出一个具体异常对象。使用方式是:
throw new IllegalArgumentException("参数错误");
此时程序将立即终止当前位置执行,并跳转到调用栈上的异常处理逻辑。抛出的异常对象必须是 Throwable
的子类。
throws
是用在方法签名上的关键字,用于声明该方法可能会抛出哪些受检异常。调用方在使用该方法时,必须处理或继续抛出这些异常。例如:
public void readFile() throws IOException { ... }
throws
声明多个异常时以逗号分隔,若子类重写父类方法,所声明异常范围不能比父类更宽泛。
总结:
throw
:抛出一个异常对象,位置在方法内部throws
:声明可能抛出哪些异常,位置在方法签名
理解两者关系,是深入掌握异常机制和构建可靠方法契约的关键。
Error 和 Exception 的区别?
Java 异常体系中,Throwable
是所有错误与异常的根类,分为 Error
和 Exception
两大类。
Error:
表示系统级错误,通常是 JVM 层面的内部故障,程序无法也不应尝试处理。例如:
OutOfMemoryError
:内存耗尽StackOverflowError
:递归调用过深导致栈空间溢出VirtualMachineError
:虚拟机内部崩溃
这些错误通常表示系统处于不可恢复状态,适合直接终止程序或等待 JVM 自动处理。
Exception:
表示程序在运行过程中遇到的可预期问题,是代码级逻辑错误或外部输入异常引起的,开发者应通过捕获、重试或兜底处理机制予以解决。典型如:
NullPointerException
:空引用访问IOException
:文件读写失败SQLException
:数据库连接异常
try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
Java 的异常处理机制规定:finally
块无论是否发生异常、是否有 return、是否抛出异常,只要执行到了 try-catch
结构,就一定会在最后执行 finally
中的代码。
即使 try
或 catch
中包含 return
语句,JVM 会在真正返回前先执行 finally
中的代码。
例如:
public int test() {
try {
return 1;
} catch (Exception e) {
return 2;
} finally {
System.out.println("finally 执行");
}
}
执行结果中一定包含 "finally 执行"
。
但如果 finally
中也包含 return
,它会覆盖 try
或 catch
中原本的返回值,造成意外的结果。
因此,建议不要在 finally
中写 return 语句,避免程序逻辑混乱与可维护性下降。
finally 一定会被执行吗?
Java 中 finally
块的设计初衷是无论是否发生异常,都能执行清理资源、关闭连接等收尾逻辑。但以下几种特殊情况会导致它无法执行:
- 程序未进入
try
块:例如在进入之前已return
,那么finally
块不会被触发。 - JVM 终止线程:如使用
System.exit(0)
,线程被强制中止,finally
不会执行。 - 异常未被捕获,JVM 崩溃:如连续抛出未捕获的严重错误导致线程死亡,可能来不及进入
finally
。 - 物理中断:极端情况如断电、操作系统崩溃、kill -9 等,会中断所有执行。
因此虽然 finally
块"尽可能"会被执行,但不能视为绝对保障,关键清理逻辑(如数据库关闭)应搭配 try-with-resources 或资源守卫机制实现更安全的保障。
总结:99% 情况下 finally 会执行,但并非绝对。
