• [编织消息框架][JAVA核心技术]异常基础


    Java异常体系结构

    Thorwable类所有异常和错误的超类,有两个子类Error和Exception,分别表示错误和异常。
    其中异常类Exception又分为运行时异常(RuntimeException)和编译时异常(checked Exception),
    下面将详细讲述这些异常之间的区别与联系:

    1.Error与Exception

    Error是程序无法处理的错误,比如OutOfMemoryError、ThreadDeath等。这些异常发生时, Java虚拟机(JVM)一般会选择线程终止。

    Exception是程序本身可以处理的异常,这种异常分两大类运行时异常和非运行时异常。 程序中应当尽可能去处理这些异常。

    2.运行时异常和编译时异常

    运行时异常都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,
    这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的。

    编译时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。
    从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。

    3.异常链

    设计目的是清晰知道程序出错调用流程,也就是传递性,一般只关心第一个跟最后一个异常信息

    源码分析

    分三部份:

    1.构造异常

    2.注册当前异常到异常列表深度坐标

    3.打印异常链

    第一部份:每次构造异常类时会调用顶级类Throwable构造方法

        public Exception(String message) {
            super(message);
        }
     
        public Exception(String message, Throwable cause) {
            super(message, cause);
        }
       
       public Throwable(String message) { fillInStackTrace(); detailMessage = message; } public Throwable(String message, Throwable cause) { fillInStackTrace(); detailMessage = message; this.cause = cause; }

    第二部份:注册到异常列表

        public synchronized Throwable fillInStackTrace() {
            if (stackTrace != null ||
                backtrace != null /* Out of protocol state */ ) {
            //插入异常列表 0 代表插入到第一,也就是说最后一个异常放到头部
                fillInStackTrace(0);
                stackTrace = UNASSIGNED_STACK;
            }
            return this;
        }
    
        private native Throwable fillInStackTrace(int dummy);

    第三部份:打印异常链,由于最后异常注册到头部,所以循环输出顺序是从尾到头

     1     public void printStackTrace() {
     2         printStackTrace(System.err);
     3     }
     4 
     5     public void printStackTrace(PrintStream s) {
     6         printStackTrace(new WrappedPrintStream(s));
     7     }
     8 
     9     private void printStackTrace(PrintStreamOrWriter s) {
    10         // Guard against malicious overrides of Throwable.equals by
    11         // using a Set with identity equality semantics.
    12         Set<Throwable> dejaVu =
    13             Collections.newSetFromMap(new IdentityHashMap<Throwable, Boolean>());
    14         dejaVu.add(this);
    15 
    16         synchronized (s.lock()) {
    17             // Print our stack trace
    18             s.println(this);
    19             StackTraceElement[] trace = getOurStackTrace();
    20             for (StackTraceElement traceElement : trace)
    21                 s.println("	at " + traceElement);
    22 
    23             // Print suppressed exceptions, if any
    24             for (Throwable se : getSuppressed())
    25                 se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "	", dejaVu);
    26 
    27             // Print cause, if any
    28             Throwable ourCause = getCause();
    29             if (ourCause != null)
    30                 ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
    31         }
    32     }
    33     
    34     public StackTraceElement[] getStackTrace() {
    35         return getOurStackTrace().clone();
    36     }
    37 
    38     private synchronized StackTraceElement[] getOurStackTrace() {
    39         // Initialize stack trace field with information from
    40         // backtrace if this is the first call to this method
    41         if (stackTrace == UNASSIGNED_STACK ||
    42             (stackTrace == null && backtrace != null) /* Out of protocol state */) {
    43             int depth = getStackTraceDepth();
    44             stackTrace = new StackTraceElement[depth];
    45             for (int i=0; i < depth; i++)
    46                 stackTrace[i] = getStackTraceElement(i);
    47         } else if (stackTrace == null) {
    48             return UNASSIGNED_STACK;
    49         }
    50         return stackTrace;
    51     }
    打印异常链

    4.追踪出错代码

    第一个输出是最后一个异常:也就是说可以追踪到最外层出错方法

    最后一个输出是第一个异常:也就是说追踪到出错的源头

    来个示例说明:

     1 package com.eyu.onequeue;
     2 
     3 public class TestException {
     4     public static void main(String[] args) {
     5         new TestException().demo();
     6     }
     7 
     8     public void a() {
     9         try {
    10             b();
    11         } catch (Exception e) {
    12             throw new RuntimeException("call a", e);
    13         }
    14 
    15     }
    16 
    17     public void b() {
    18         try {
    19             c();
    20         } catch (Exception e) {
    21             throw new RuntimeException("call b", e);
    22         }
    23     }
    24 
    25     public void c() {
    26         throw new RuntimeException("call c");
    27     }
    28 
    29     public void demo() {
    30         a();
    31     }
    32 }

    Exception in thread "main" java.lang.RuntimeException: call a
      at com.eyu.onequeue.TestException.a(TestException.java:12)
      at com.eyu.onequeue.TestException.demo(TestException.java:30)
      at com.eyu.onequeue.TestException.main(TestException.java:5)
    Caused by: java.lang.RuntimeException: call b
      at com.eyu.onequeue.TestException.b(TestException.java:21)
      at com.eyu.onequeue.TestException.a(TestException.java:10)
    ... 2 more
    Caused by: java.lang.RuntimeException: call c
      at com.eyu.onequeue.TestException.c(TestException.java:26)
      at com.eyu.onequeue.TestException.b(TestException.java:19)
    ... 3 more

    c方法是出错的源头,a方法是调用者

    小提示:当异常信息太多时,过滤条件以项目包名或类名能快速定位出错源头,一般是应用程序逻辑出错

    下节利用异常开发项目

    最后给出jdk常见异常

  • 相关阅读:
    mybatis和spring整合
    Freemarker教程1(基本使用)
    mybatis教程6(逆向工程)
    mybatis教程4(动态SQL)
    mybatis教程5(延迟加载和缓存)
    mybatis教程2(配置文件)
    python作用域
    软件测试基础面试题
    http协议
    selenium自动化测试
  • 原文地址:https://www.cnblogs.com/solq111/p/6604332.html
Copyright © 2020-2023  润新知