美文网首页
关于异常

关于异常

作者: lionel880 | 来源:发表于2017-12-15 15:34 被阅读0次

    参考资料:JVM如何处理异常深入详解

    一、Java 异常的概念和分类

    所有的异常都派生于Throwable类的一个实例


    无标题.jpg

    Error

    java 运行时的系统错误和资源耗尽错误。 应用程序是不应该跑出这种类型的对象。一般出现错误,也没什么办法

    Exception

    RunTimeException和其他Exception(主要是IO Exception)

    RunTimeException:为程序的逻辑错误
    如:类型错误,数组越界,空指针
    其他Exception(主要是IO Exception):程序本身没问题,但由于像I/O这样的错误导致异常
    如:打开一个不存在的文件,根据字符串找class炸不到等

    unchecked 和checked

    java将error和RunTimeException归为unchecked 异常,其他为checked 异常

    原则上checked 异常要进行声明,而unchecked 异常要么控制不了,如error,要么应该避免发生RunTimeException,不需要捕获

    二、JVM如何处理异常

    异常表 Exception Table

    • 异常表的构成
      from 可能发生异常的起始点
      to 可能发生异常的结束点
      target 上述from和to之前发生异常后的异常处理者的位置
      type 异常处理者处理的异常的类信息

    • 异常表的调用
      1.JVM会在当前出现异常的方法中,查找异常表,是否有合适的处理者来处理
      2.如果当前方法异常表不为空,并且异常符合处理者的from和to节点,并且type也匹配,则JVM调用位于target的调用者来处理。
      3.如果上一条未找到合理的处理者,则继续查找异常表中的剩余条目
      4.如果当前方法的异常表无法处理,则向上查找(弹栈处理)刚刚调用该方法的调用处,并重复上面的操作。
      5.如果所有的栈帧被弹出,仍然没有处理,则抛给当前的Thread,Thread则会终止。
      6.如果当前Thread为最后一个非守护线程,且未处理异常,则会导致JVM终止运行。

    • catch的顺序
      catch的顺序决定了异常处理者在异常表的位置
      因为我们实际中可以catch很多的exception 类型,所以越具体的exception要放在前面,宽泛的exception或者throwable一般都用于兜底

    • finally的执行
      finally是如何真正执行的,当前编译器的做法是复制finnal 代码块的内容,分别放在try-catch代码块的所有正常执行路径和异常执行路径的出口中

    public static void XiaoXiao() {
       try {
           dada();
       } catch (Exception e) {
           e.printStackTrace();
       } finally {
           System.out.println("Finally");
       }
    }
    //通过javap 反编译
    public static void XiaoXiao();
        Code:
           0: invokestatic  #3                  // Method dada:()V
           3: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
           6: ldc           #7                  // String Finally
           8: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
          11: goto          41
          14: astore_0
          15: aload_0
          16: invokevirtual #5                  // Method java/lang/Exception.printStackTrace:()V
          19: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
          22: ldc           #7                  // String Finally
          24: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
          27: goto          41
          30: astore_1
          31: getstatic     #6                  // Field java/lang/System.out:Ljava/io/PrintStream;
          34: ldc           #7                  // String Finally
          36: invokevirtual #8                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
          39: aload_1
          40: athrow
          41: return
        Exception table:
           from    to  target type
               0     3    14   Class java/lang/Exception
               0     3    30   any
              14    19    30   any
    

    这三份finally代码块都放在什么位置:
    第一份位于try代码后 : 若果try中代码正常执行,没有异常那么finally代码就在这里执行。
    第二份位于catch代码后 : 如果try中有异常同时被catch捕获,那么finally代码就在这里执行。
    第三份位于异常执行路径 : 如果如果try中有异常但没有被catch捕获,或者catch又抛异常,那么就执行最终的finally代码

    • return 和 finally
      这个其实不必要强记,只需要你知道java编译器的原理就可以了,java编译器将finally编译进去后,如果有return是先执行finnal在执行return的
    invokestatic #3   // Method testNPE:()V
     3: ldc  #6   // String OK
     5: astore_0
     6: getstatic #7   // Field java/lang/System.out:Ljava/io/PrintStream;
     9: ldc  #8   // String tryCatchReturn
     11: invokevirtual #9   // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     14: aload_0
     15: areturn 返回OK字符串,areturn意思为return a reference from a method
    

    三、未捕获异常是如何处理的

    当一个线程遇到的异常,并没有被正确的捕获,就成为了未捕获异常,如没有catch或catch没有兜底的exception和throwable

    • 如何设置未捕获异常


      image.png
    • 线程发生uncaughtException,JVM怎么处理
      1.每个线程有一个变量uncaughtExceptionHandler来保存未捕获异常的handle
      2.线程分发目标的handle,优先分发给当前线程的uncaughtExceptionHandler
      3.上述为null时,分发给自己所在的ThreadGroup来作为未捕获异常处理者,ThreadGroup implements Thread.UncaughtExceptionHandler
      4.ThreadGroup会尝试转给它的父ThreadGroup(如果存在的话)
      5.如果上面没有找到对应的ThreadGroup,则尝试获取Thread.getDefaultUncaughtExceptionHandler()并分发

    相关文章

      网友评论

          本文标题:关于异常

          本文链接:https://www.haomeiwen.com/subject/rzrdwxtx.html