异常处理全面解析

checked和unchecked异常

  • checked 异常(检查型异常)在源代码里必须显式地捕获或者抛出,否则编译器会提示你进行相应的操作;而 unchecked 异常(非检查型异常)就是所谓的运行时异常,通常是可以通过编码进行规避的,并不需要显式地捕获或者抛出。

  • NoClassDefFoundError:程序在编译时可以找到所依赖的类,但是在运行时找不到指定的类文件,导致抛出该错误;原因可能是 jar 包缺失或者调用了初始化失败的类。

  • ClassNotFoundException:当动态加载 Class 对象的时候找不到对应的类时抛出该异常;原因可能是要加载的类不存在或者类名写错了。

throw和throws

1)throws关键字用于声明异常,它的作用和try-catch相似;而throw关键字用于显式的抛出异常。

throws ArithmeticException;

2)throws关键字后面跟的是异常的名字;而throw关键字后面跟的是异常的对象。

throw new ArithmeticException("算术异常");

3)throws关键字出现在方法签名上,而throw关键字出现在方法体里。

4)throws关键字在声明异常的时候可以跟多个,用逗号隔开;而throw关键字每次只能抛出一个异常。

  • 如果有好几个类似的方法都可能出现异常,如果为每个方法都加上try-catch,就会显得非常繁琐。一个解决办法就是,使用throws关键字,在方法签名上声明可能会抛出的异常,然后在调用该方法的地方使用try-catch进行处理。
public static void main(String args[]){
    try {
        myMethod1();
    } catch (ArithmeticException e) {
        // 算术异常
    } catch (NullPointerException e) {
        // 空指针异常
    }
}
public static void myMethod1() throws ArithmeticException, NullPointerException{
    // 方法签名上声明异常
}

try-catch-finally

  • 一个 try 块后面可以跟多个 catch 块,用来捕获不同类型的异常并做相应的处理,当 try 块中的某一行代码发生异常时,之后的代码就不再执行,而是会跳转到异常对应的 catch 块中执行。

  • 如果一个 try 块后面跟了多个与之关联的 catch 块,那么应该把特定的异常放在前面,通用型的异常放在后面,不然编译器会提示错误。

  • finally 块前面必须有 try 块,不要把 finally 块单独拉出来使用。编译器也不允许这样做。

  • finally 块不是必选项,有 try 块的时候不一定要有 finally 块。

  • 如果 finally 块中的代码可能会发生异常,也应该使用 try-catch 进行包裹。

  • 即便是 try 块中执行了 return、break、continue 这些跳转语句,finally 块也会被执行

  • 不执行finally的情况:遇到了死循环;执行了 System. exit() 这行代码。

class MyFinallyReadLineThrow {
    public void close() throws Exception {
        throw new Exception("close");
    }

    public void readLine() throws Exception {
        throw new Exception("readLine");
    }
}

public class Test {
    public static void main(String[] args) throws Exception {
        MyFinallyReadLineThrow myThrow = null;
        try {
            myThrow = new MyFinallyReadLineThrow();
            // readLine的异常信息丢失
            myThrow.readLine();
        } finally {
            myThrow.close();
        }
        /*
        Exception in thread "main" java.lang.Exception: close
            at test.ExceptionTest.MyFinallyReadLineThrow.close(Test.java:5)
            at test.ExceptionTest.Test.main(Test.java:21)
         */
    }
}

try-with-resources

  • 当一个异常被抛出的时候,可能有其他异常因为该异常而被抑制住,从而无法正常抛出。这时可以通过 addSuppressed() 方法把这些被抑制的方法记录下来,然后被抑制的异常就会出现在抛出的异常的堆栈信息中,可以通过 getSuppressed() 方法来获取这些异常。这样做的好处是不会丢失任何异常,方便我们进行调试。
package test.ExceptionTest;

class MyFinallyReadLineThrow implements AutoCloseable {
    @Override
    public void close() throws Exception {
        throw new Exception("close");
    }

    public void readLine() throws Exception {
        throw new Exception("readLine");
    }
}


public class Test {
    public static void main(String[] args) {
        try (MyFinallyReadLineThrow myThrow = new MyFinallyReadLineThrow()) {
            myThrow.readLine();
        } catch (Exception e) {
            e.printStackTrace();
        }
        /*
        java.lang.Exception: readLine
            at test.ExceptionTest.MyFinallyReadLineThrow.readLine(Test.java:10)
            at test.ExceptionTest.Test.main(Test.java:18)
            Suppressed: java.lang.Exception: close
               at test.ExceptionTest.MyFinallyReadLineThrow.close(Test.java:6)
               at test.ExceptionTest.Test.main(Test.java:19)
         */
    }
}
posted @ 2024-07-13 23:25  n1ce2cv  阅读(14)  评论(0编辑  收藏  举报