科学的解决Java程序的异常

前言

最近工作的过程中遇到了一些异常,所以解决异常的操作不够系统化,总结一下,示例如下。

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类属性。

  1. 导致异常的原因(cause)
  2. 发生异常时的详细解释信息(message)
  3. 异常的栈帧跟踪数组(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。

  1. Checked Exception,这个就是我们在编辑的时候,一些智能一点的ide都会提醒我们这条语句可能会有异常,要么加try catch在方法内总结解决,要么用throws加到方法上扔给上一级处理。说实话我觉得叫做编辑期异常更容易理解,叫做受检异常有点不对劲。

  2. 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. 第1行是异常类型(class)加上异常的信息(message)
  2. 第2,3,4行是从栈帧跟踪数组里面遍历数组元素得到的信息
  3. 假如自定义一个异常然后把捕捉到的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自己集成的图形化界面了。

image.png

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容