Throwable
Error
Exception
VirtualMachineError
ThreadDeath
RuntimeException
IOException
ArrayIndexOutOfBoundsException
ArithmeticException
IllegalArgumentException
ArrayStoreException
NegativeArraySizeException
NullPointerException
SecurityException
EOFException
FileNotFoundException
写在前面

一个方法通常有个程序出口,当方法不能被正确执行完毕时候,会以另一种方式执行完毕,这种执行方式就是异常的执行。

Java 中所有异常都有个共同祖先 Throwable,其有两个重要子类 Exception(异常)和 Error(错误),Error Java 编译器无法检查的,Exception 主要分为 RuntimeException 和其他非 RuntimeException 的异常,由于 RuntimeException 诸如数组越界这些异常时 Java 编译器在编译阶段无法发现的,只有程序运行到这一步才能报出异常,所以运行异常又称为不可查异常(unchecked exceptions)非运行异常又称可查异常(checked exceptions),像数组越界的异常等都属于运行异常(不可查异常),像一些代码逻辑错误和一些 IO 操作抛出的都是非运行异常(可查异常)

Throwable 类
  • 其及其子类有两个构造方法,一个不带参数,一个带 String 参数
  • 为什么要实现 Serializable 接口,因为将对象状态保存在存储媒体中以便在以后重新创建处完全相同的副本,还有可以按值将对象从一个应用程序域发送到另一个应用程序域。通俗说就是分布式应用中,你就得实现序列化。实际上 Java 很多类都实现了 Serializable 接口
  • 其下有 Error(不可检查)和 Exception(分可查和不可查)两大类
  • try catch可以捕获其及其子类对象的抛出,但是try catch效率非常低下
Error 类
  • 它们都在java.lang

  • 一般是程序中严重的错误,如虚拟机层面错误,一旦发生程序本身无法正常处理,通常和 JVM 内存区域脱不了关系,一旦程序出了 Error,我们建议去看一看 heap dump,修改下 JVM 参数,发生了 Error 程序直接崩掉,用 Java 代码的方式无法弥补

  • 可以throw抛出但是无法try catch捕获

  • OutOfMemoryError(OOM) 内存溢出错误,通常发生在 Java 堆上

  • StackOverflowError(SO) 栈溢出错误,常发生在递归过深的情况,常常发生在虚拟机栈上

Exception 类
  • 它们都在java.lang

  • 其可分为运行时异常(RuntimeException)和非运行异常(如 IOException),有很多异常都是运行时异常,Java 不强行对这类异常进行捕获,仍可进行手工捕获来避免意外,对运行时异常进行进一步划分:

    • 可预测异常(PE):一般由代码错误或外部因素,如空指针,数组越界
    • 警告级异常(CE):需要显示的捕获处理,否则程序不可用,如 TimeoutException
    • 可忽略异常(IE):程序可自行处理的异常,程序员可忽略,这类异常不由程序员捕捉
  • 非运行异常有如 SQLExceptionClassNotFoundExceptionCloneNotSupportedExceptionIllegalAccessExceptionInterruptedExceptionNoSuchFieldExceptionNoSuchMetodExceptionIOExceptionEOFExceptionFillNotFoundException

  • 对于运行时异常为 RuntimeException 及其子类,发生异常时候我们无需在方法上向上抛出,也没有必要去 try catch 处理,发生异常基本就是代码问题,需要修改

  • 对于非运行时异常的产生,我们需要向上抛出,如果不想再抛出需要进行 try catch 捕获自行做处理

自定义异常

对于项目中的自定义异常我们一般是继承 RuntimeException 运行时异常类(下面例子中是继承 Exception 类)

/**
 * 自定义异常类继承 Exception
 * 重写父类构造器
 */
public class MyException extends Exception{
    public MyException(){
		super();
	}
    public MyException(String str){
        super(str);
    }
}

/**
 * 测试类
 */
public class MyTest{
    public void testMyException(){
        // 产生随机数,1 或者 2
        Random r = new Random();
        int x = r.nextInt(2) + 1;
        // 判断
        if(x == 1){
            System.out.println("随机数是 1");
        }
        else{
            // 捕获自定义异常
            try{
                // 抛出自定义异常
                throw new MyException("随机数是 2 不是 1 !");
            } catch (MyException e) {
                e.printStackTrace();
            } finally {
                System.out.println("不论是否捕获了异常这里都将执行");
            }
        }
    }
}
其他

对于底层代码是如何实现异常的以及 JVM 底层是如何处理异常的机理