Throwable
所有错误与异常的超类,包含两个子类:Error 和 Exception
Error
程序中无法处理的错误,表示运行应用程序中出现了严重的错误。
此类错误一般表示代码运行时 JVM 出现问题。通常有 Virtual MachineError(虚拟机运行错误)、NoClassDefFoundError(类定义错误)等。比如 OutOfMemoryError(内存不足错误)、StackOverflowError(栈溢出错误)。此类错误发生时,JVM 将终止线程。
Exception
程序本身可以捕获并且可以处理的异常。Exception 这种异常又分为两类:
运行时异常
RuntimeException 类及其子类,表示 JVM 在运行期间可能出现的异常。
Java 编译器不会检查它。当程序中可能出现这类异常时,倘若既"没有通过throws声明抛出它",也"没有用try-catch语句捕获它",还是会编译通过。比如 NullPointerException 空指针异常、ArrayIndexOutBoundException 数组下标越界异常、ClassCastException 类型转换异常。
此类异常属于不受检异常,一般是由程序逻辑错误引起的,在程序中可以选择捕获处理,也可以不处理。虽然编译器不会检查运行时异常,但是可以通过throws进行声明抛出,也可以通过try-catch对它进行捕获处理。如果产生运行时异常,则需要通过修改代码来进行避免。例如,若会发生除数为零的情况,则需要通过代码避免该情况的发生!
RuntimeException异常会由Java虚拟机自动抛出并自动捕获,此类异常的出现绝大数情况是代码本身有问题应该从逻辑上去解决并改进代码。
编译时异常
Exception 中除 RuntimeException 及其子类之外的异常。
Java编译器会检查它。如果程序中出现此类异常,比如 ClassNotFoundException(没有找到指定的类异常),IOException(IO流异常),要么通过 throws 进行声明抛出,要么通过 try-catch 进行捕获处理,否则不能通过编译。
在程序中,通常不会自定义该类异常,而是直接使用系统提供的异常类。该异常我们必须手动在代码里添加捕获语句来处理该异常。
JVM 如何处理异常
在一个方法中如果发生异常,这个方法会创建一个异常对象,并转交给 JVM,该异常对象包含异常名称、异常描述以及异常发生时应用程序的状态。JVM 会顺着调用栈去查找看是否有可以处理异常的代码,如果有,则调用异常处理代码。如果没有找到可以处理该异常的代码块,JVM 就会将该异常转交给默认的异常处理器,默认异常处理器打印出异常信息并终止应用程序。