前言
最近工作的过程中遇到了一些异常,所以解决异常的操作不够系统化,总结一下,示例如下。
public class Fault {
public static void main(String[] args) {
Fault fault = new Fault();
fault.solveFault(3);
}
public void solveFault(int j){
Solve kick = new Solve(3, "kick");
kick.setAge(kick.getAge()-j);
solve(kick.getAge());
}
public void solve(int i){
int j = 8/i;
}
}
class Solve {
private int age;
private String name;
//接下来age和name的构造方法和setter和getter,我就不写了
.......
}
显然以上结果会报异常,报异常结果如下
1. java.lang.ArithmeticException: / by zero
2. at Fault.solve(Fault.java:13)
3. at Fault.solveFault(Fault.java:9)
4. at Fault.main(Fault.java:4)
看懂报异常结果
首先要分析报异常结果,就有必要分析一下异常有什么属性,异常主要包括3类属性。
- 导致异常的原因(cause)
- 发生异常时的详细解释信息(message)
- 异常的栈帧跟踪数组(stack trace数组)
导致异常的原因 cause
这个一般是由用try catch捕捉到的异常作为自己new的异常的一个cause,一般是作为构造参数传进去或者调用initCause(cause)方法。这样子就形成了一个链式的cause原因,因此没有自己new异常的时候基本上调用都为null。
例如把之前的solve方法改成这样子
public void solve(int i) throws Exception{
try {
int j = 8/i;
}catch (Exception e){
//或者是直接Exception exception = new Exception(e);
Exception exception = new Exception();
exception.initCause(e);
throw exception;
}
}
异常的附带信息 message
这里吐槽一些,为什么我们喜欢把英文直译过来呢?例如Exception里面分两类Checked Exception和Runtime Exception。
Checked Exception,这个就是我们在编辑的时候,一些智能一点的ide都会提醒我们这条语句可能会有异常,要么加try catch在方法内总结解决,要么用throws加到方法上扔给上一级处理。说实话我觉得叫做编辑期异常更容易理解,叫做受检异常有点不对劲。
Runtime Exception,这个就是你运行起来出现的异常,叫做运行时异常这个就直译可以。
这个message在发生jdk自带的异常的时候一般都会有的,然后就看你自己new的异常能不能好好处理它这个jdk自带的异常了。
异常的栈帧跟踪数组 stack trace数组
stack tarck数组中可以把他理解成一个栈,数组后面是栈底,数组前面是栈顶,然后方法调用就是压栈,里面存储的是StackTraceElement对象,这个对象里面可以找到每个方法出错的文件,类,方法名,行数
# 可以把上面try catch里面的换成这个
Arrays.stream(e.getStackTrace()).forEach(
k->{System.out.println("在"+k.getClassName()+"的"+k.getMethodName()+"方法.\n"
+k.getFileName()+"文件的第"+k.getLineNumber()+"行出现错误");});
# 然后会出现下面的结果
在Fault的solve方法.
Fault.java文件的第21行出现错误
在Fault的solveFault方法.
Fault.java文件的第12行出现错误
在Fault的main方法.
Fault.java文件的第6行出现错误
报异常结果的总结
现在回到之前的报异常结果。
- 第1行是异常类型(class)加上异常的信息(message)
- 第2,3,4行是从栈帧跟踪数组里面遍历数组元素得到的信息
- 假如自定义一个异常然后把捕捉到的exception注入进去,那么后面还会出现caused by,就像这样
java.lang.Exception: java.lang.ArithmeticException: / by zero
at Fault.solve(Fault.java:23)
at Fault.solveFault(Fault.java:12)
at Fault.main(Fault.java:6)
Caused by: java.lang.ArithmeticException: / by zero
at Fault.solve(Fault.java:21)
... 2 more
了解debug
从上面我们已经了解到了出问题的地方在那些语句,哪几行了,一般情况下其实就可以解决部分问题了,但是还有一部分是需要debug解决的。其实java的debug调用用的是jdb。jdb和gdb原理都是差不多的,或者说debug是在所有程序里面都差不多的,gdb的使用看我之前的文章gdb的简单使用 - 简书 (jianshu.com),这里jdb的使用我是直接用ide自己集成的图形化界面了。

到自己要判断的行的附近debug就可以找到错误了。