欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 后台管理


新闻资讯

MENU

软件开发知识

所以在此 劳务派遣管理系统 处省略

点击: 次  来源:宝鼎软件 时间:2017-11-08

原文出处: 猴子007

给出如下异常信息:

java.lang.RuntimeException: level 2 exception
	at com.msh.demo.exceptionStack.Test.fun2(Test.java:17)
	at com.msh.demo.exceptionStack.Test.main(Test.java:24)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
Caused by: java.io.IOException: level 1 exception
	at com.msh.demo.exceptionStack.Test.fun1(Test.java:10)
	at com.msh.demo.exceptionStack.Test.fun2(Test.java:15)
	... 6 more

学这么多年Java,你真的会阅读Java的异常信息吗?你能说清楚异常抛出进程中的事件顺序吗?

需要内化的内容

写一个demo测试

上述异常信息在由一个demo发生:

package com.msh.demo.exceptionStack;
import java.io.IOException;
/**
 * Created by monkeysayhi on 2017/10/1.
 */
public class Test {
  private void fun1() throws IOException {
    throw new IOException("level 1 exception");
  }
  private void fun2() {
    try {
      fun1();
    } catch (IOException e) {
        throw new RuntimeException("level 2 exception", e);
    }
  }
  public static void main(String[] args) {
    try {
      new Test().fun2();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

这次我复制了完整的文件内容,使文章中的代码行号和实际行号一一对应。
按照上述异常信息,异常抛出进程中的事件顺序是:

  • 在Test.java的第10行,抛出了一个IOExceotion(“level 1 exception”) e1
  • 异常e1被逐层向外抛出,直到在Test.java的第15行被捕捉
  • 在Test.java的第17行,按照捕捉的异常e1,抛出了一个RuntimeException(“level 2 exception”, e1) e2
  • 异常e2被逐层向外抛出,直到在Test.java的第24行被捕捉
  • 后续没有其他异常信息,颠末须要的框架后,由措施自动或用户主动挪用了e2.printStackTrace()要领
  • 如何阅读异常信息

    那么,如何阅读异常信息呢?有几点你需要认识清楚:

  • 异常栈以FILO的顺序打印,位于打印内容最下方的异常最早被抛出,逐渐导致上方异常被抛出。位于打印内容最上方的异常最晚被抛出,且没有再被捕捉。从上到下数,第i+1个异常是第i个异常被抛出的原因cause,以“Caused by”开头。
  • 异常栈中每个异常都由异常名+细节信息+路径构成。异常名从行首开始(或紧随”Caused by”),紧接着是细节信息(为加强可读性,昆山软件开发,需要提供得当的细节信息),从下一行开始,跳过一个制表符,就是路径中的一个位置,一行一个位置。
  • 路径以FIFO的顺序打印,位于打印内容最上方的位置最早被该异常颠末,逐层向外抛出。最早颠末的位置等于异常被抛出的位置,逆向debug时可以后处开始;后续位置一般是要领挪用的进口,JVM捕捉异常时可以从要领栈中获得。对付cause,其可打印的路径截至到被包装进下一个异常之前,之后打印“… 6 more”,暗示cause作为被包装异常,在这之后还逐层向外颠末尾6个位置,但这些位置与包装异常的路径反复,所以在此处省略,而在包装异常的路径中打印。“… 6 more”的信息不重要,可以忽略。
  • 此刻,回过甚再去阅读示例的异常信息,是不是相当简朴?

    为了辅佐领略,我尽大概通俗易懂的描写了异常信息的布局和构成元素,大概会引入一些马虎。阅读异常信息是Java措施猿的根基技术,但愿你能内化它,忘掉这些冗长的描写。

    假如还不领略,发起你亲自追踪一次异常的建设和打印进程,利用示例代码即可,它很简朴但足够。难点在于异常是JVM提供的机制,你需要相识JVM的实现;且底层挪用了许多native要领,而追踪native代码没有那么利便。

    扩展

    为什么有时我在日志中只看到异常名”java.lang.NullPointerException”,却没有异常栈

    示例的异常信息中,异常名、细节信息、路径三个元素都有,可是,由于JVM的优化,细节信息和路径大概会被省略。

    这常常产生于处事器应用的日志中,由于沟通异常已被打印多次,假如继承打印沟通异常,JVM会省略掉细节信息和路径行列,向前翻阅即可找到完整的异常信息。

    猴哥之前利用Yarn的Timeline Server时碰着过该问题。你能体会那种感受吗?卧槽,为什么只有异常名没有异常栈?没有异常栈怎么老子怎么知道那边抛出的异常?线上处事老子又不能停,劳务派遣管理系统,全靠日志了啊喂!

    网上有不少沟通的case,好比NullPointerException丢失异常仓库信息,读者可以参照这个链接尝试一下。

    如安在异常类中添加成员变量

    为了得当的表达一个异常,我们有时候需要自界说异常,并添加一些成员变量,打印异常栈时,自动增补打印须要的信息。