了解 java 错误堆栈产生流程

来源:互联网 发布:淘宝提升销量的方法 编辑:程序博客网 时间:2024/05/06 11:54

一、项目结构:

这里写图片描述

二、代码:

  1. BizException:

    package com.exception;/**   * 自定义业务逻辑错误类 *  * 之所以让它继承了 RuntimeException 是因为 * java 中 RuntimeException 默认都定义在了 throws 中了 * 所以不需要我们显示的去处理,就会一层层的往上抛 *  * ClassName:BizException <br/>   * Date:     2017年3月23日 上午10:35:38 <br/>   * @author   ztd   * @version     * @see         */public class BizException extends RuntimeException {    private static final long serialVersionUID = 1L;    public static final BizException NO_RECORD = new BizException(302, "没有此记录");    private int code;    private String msg;    public BizException() {        super();      }    public BizException(int code, String msg) {        super(msg);        this.code = code;        this.msg = msg;    }    public int getCode() {        return code;    }    public void setCode(int code) {        this.code = code;    }    public String getMsg() {        return msg;    }    public void setMsg(String msg) {        this.msg = msg;    }}
  2. TestBizException

    package com.exception;/**   * ClassName:TestBizException <br/>   * Date:     2017年3月23日 上午10:43:14 <br/>   * @author   ztd   * @version     * @see         */public class TestBizException {    public static void main(String[] args) {        get(10);    }    public static void get(int id) {        getStation(id);    }    public static void getStation(int id) {        if(id > 5) {            throw BizException.NO_RECORD;        }    }}
  3. 测试结果
    截图:
    这里写图片描述
Exception in thread "main" com.exception.BizException: 没有此记录    at com.exception.BizException.<clinit>(BizException.java:19)    at com.exception.TestBizException.getStation(TestBizException.java:27)    at com.exception.TestBizException.get(TestBizException.java:22)    at com.exception.TestBizException.main(TestBizException.java:18)

三、错误堆栈分析

从打印的错误堆栈上来看,我们可以把堆栈信息分为几部分:下面根据上面截图标注的1,2,3来逐个分析:

  1. 错误的基本信息:就是我们看到的错误的第一行:告诉我们出现了什么错误
  2. 抛出错误的位置:这个位置就是错误抛出的位置
  3. 错误调用链:我们可能写了很多代码,代码之间有很多的相互调用,这个地方就是错误在引发前的一系列的调用流程

    错误定位方法总结:

首先:了解错误的基本信息(位置1):明白这是一个什么错误
其次:查找错误的抛出位置(位置2):找出是因为哪一个条件没有满足才抛出的这个错误。
最后:找出触发错误的代码(位置3):从错误调用链中一行一行的分析,找出代码中哪一行的变量没有满足这个错误的检查,改掉这里错误就解决了。

四、扩展

从上面我们知道分写一个错误的基本流程虽然不是很难,但是如果代码的调用链如果变得非常长,非常复杂的时候,这个查找过程就会变得复杂和漫长,因此为了在开发中快速的定位问题,让我们的代码变得健壮,我们就需要对传递过来的参数变量进行检查对不符合要求的代码直接抛出错误,这样的话就会把错误的抛出链条变短,问题更容易定位。

举例:

public OrderStosteBO updateByOrderSnAndStosteId(OrderStosteBO orderStosteBO) {        OrderStoste orderStoste = BeanMapper.map(orderStosteBO, OrderStoste.class);        OrderStosteQuery query = new OrderStosteQuery();        query.createCriteria().andOrderSnEqualTo(orderStosteBO.getOrderSn()).andStosteIdEqualTo(orderStosteBO.getStosteId());        int influenceNumber = orderStosteMapper.updateByExampleSelective(orderStoste, query);        if(influenceNumber != 1) {            logger.info("{} update failure , id is {}", "t_stoste", orderStoste.getOrderSn());            throw new RpcException(ExceptionStatus.UPDATE_ERROR.getCode(), ExceptionStatus.UPDATE_ERROR.getMessage());        }        OrderStosteBO result = this.select(orderStoste.getId());        return result;    }    @Override    public OrderStosteBO select(Integer id) {        if(null == id) {            throw new RuntimeException("id 不能为空");        }        OrderStosteQuery query = new OrderStosteQuery();        query.createCriteria().andIdEqualTo(id);        List <OrderStoste> orderStosteList = orderStosteMapper.selectByExample(query);        if(CollectionUtils.isEmpty(orderStosteList)) {            return null;        }        OrderStosteBO result = BeanMapper.map(orderStosteList.get(0), OrderStosteBO.class);        return result;    }

这一段代码中方法 updateByOrderSnAndStosteId 调用方法 select,如果我们在方法 select 中没有添加 id 不为空的校验,那么上面方法在执行的时候,报错信息如下:
这里写图片描述

如果我们对 select 方法添加校验:

    @Override    public OrderStosteBO select(Integer id) {        if(null == id) {            throw new RuntimeException("id 不能为空");        }        OrderStosteQuery query = new OrderStosteQuery();        query.createCriteria().andIdEqualTo(id);        List <OrderStoste> orderStosteList = orderStosteMapper.selectByExample(query);        if(CollectionUtils.isEmpty(orderStosteList)) {            return null;        }        OrderStosteBO result = BeanMapper.map(orderStosteList.get(0), OrderStosteBO.class);        return result;    }

当再次出错的时候,抛出错误如下:
这里写图片描述

这样一看,错误的堆栈信息少了好几行,而且变得可读性更强了,我们定位起来也变得更加的方便了。

0 0