欢迎来到 陈本布衣 的博客小园

   认识异常

  异常基础

  所谓的异常,就是程序按照正常执行逻辑走着走着遇到问题,崴了脚或闪了腰,已经无法再继续走下去了。怎么办呢?就像有病要治病一样,有异常就得处理异常。Java提供了基本的语法来处理异常:一中是throw(s)语法,叫抛异常;一种是try-catch-finally语法,叫做捕获异常。Java是面向对象的,在Java的世界里一切皆是对象,所以异常自然也被看成是一种对象,当异常发生,就是创建了一个异常对象,我们使用两种语法来处理异常对象就行了,语法也很简单,下面只简单示例:

public class Test {

    //继续外抛异常
    public void test1() throws FileNotFoundException {
        new FileInputStream("D://test.txt");
    }

    //自己捕获异常
    public void test2() {
        try {
            new FileInputStream("D://test.txt");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally{
            //不管异常发没发生都总会执行的部分,通常用来处理收尾工作,入内存清理,关闭流等等
        }
    }

    //自己主动创建异常对象并抛出
    public void test3() throws Exception {
        throw new Exception("抛出异常");
    }

}

  这里很基础,还是说三点:

  ① 最好从英文词性上区分throw和throws两个关键字。前者是动词,代表抛出,很明显是用在方法内部,执行异常对象的抛出动作;后者是名词,用在方法后面,用来声明方法执行可能抛出的一个或多个异常,多个异常之间用逗号隔开;

  ② finally块不是必须的,除非业务中有必须要执行的部分;如果有finally块,那该部分语句无论方法是否发生异常甚至中途执行return终止方法,该部分都会得到执行;finally块中不能使用return,会造成异常丢失;

  ③ 如果你对异常是该抛出和自己处理犹豫不定,那布衣博主告诉你一个原则:该背锅背锅,不能背就甩锅!是的,异常和日常中的甩锅行为类似。当别人向你甩来的锅如果你能背,那就接住大胆背锅处理异常,不然就甩锅吧给上层调用者处理。

  异常体系

  打开JDK API 文档,找到 lang包中 Throwable类,这就是Java异常的祖宗类了。你会发现异常家族体系相当庞大,但大而不乱,因为这祖宗也就两个直接子类 Error 和 Exception。Error 通常指系统错误,程序员无需关心;Exception才是需要抛出或者捕获的异常的基类,其下有很多子类孙类,支系繁茂。对于Exception类型异常,又分了编译期异常和运行时异常两大类,前者是在编码阶段必须处理(捕获或者抛出)的异常类型,不处理程序无法正常编译;后者不用主动处理,通常是程序逻辑上的异常,在程序运行时由虚拟机抛出。只需记住如下谱系图即可:

  自定义异常

  简单封装

  Java标准类库中的异常虽然已经很多了,但是那是标准库中通用的异常情况,不同项目会有不同的业务逻辑,这就需要我们根据自己的业务逻辑来定义、处理自己的异常。最好的自定义方式是从跟自己业务处理意思最接近的异常类继承,比如定义运行时异常可以继承RuntimeException,定义IO异常可以继承IOException。不过对异常情形限定得太窄其实也没有必要了,直接继承异常基类Exception即可:

public class MyException extends Exception {
    public MyException() {
        super();
    }

    public MyException(String message) {
        super(message);
    }

    public MyException(String message, Throwable cause) {
        super(message, cause);
    }
}

  这样简单的继承,只是屏蔽了底层的具体异常类,对外暴露的是和自己业务相关的语义化的异常类名而已,功能依旧是父类异常的功能。这样的自定义异常显然功能太父类化了。更多的情况下,我们希望异常类能有比父类更完备的功能,以帮助程序向客户端调者反馈更友好的信息。这个时候要跳出异常的字面意思去理解Java的异常机制,不能简单的认为异常就是发生了不想看到的错误,而是把异常看成一种控制流,是程序流程处理的一部分,控制着我的程序在情况1 时走哪一步,在情况2下又该执行哪一步。比如通过JNA调用底层动态库获取硬件信息,由于程序运行的不可预见性,Java程序员和底层语言开发者之间会根据返回值约定一些异常情形,比如 0 代表什么,1 代表什么,诸如此类:

    public void func(int result) throws MyException1 ,MyException2,MyException3{
        switch (result){
            case 1:throw new MyException1();
            case 2:throw new MyException2();
            case 3:throw new MyException3();
            ...
        }
    }

  像上面这种,利用穷举的方式写代码肯定是很不明智的,更多的时候,我们会采用枚举与自定义异常相结合的方式,来处理异常的流程控制,以更好的发挥自定义异常的自定义作用。

  异常与枚举

   先定义约定的异常情形枚举:

//异常状态枚举
public enum ErrorCode {
    SUCCESS(0, "成功"),
    NOTFOUND(1, "未找到验证设备"),
    READFAIL(2, "读取验证设备失败"),
    OVERDUE(3, "验证设备已过期"),
    UNKNOWN(4, "未知原因的失败");

    int code;
    String msg;

    ErrorCode(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    //根据状态码获取状态信息
    public static ErrorCode getErrorCode(int code) {
        for (ErrorCode errorCode : values()) {
            if (errorCode.code == code) {
                return errorCode;
            }
        }
        return null;
    }

    @Override
    public String toString() {
        return "ErrorCode{" +
                "code=" + code +
                ", msg='" + msg + '\'' +
                '}';
    }
}

  再定义自己的异常类:

public class LibException extends Exception {

    private int code;
    private ErrorCode errorCode;


    public ErrorCode getErrorCode() {
        return errorCode;
    }


    LibException(int code) {
        this.code = code;
        this.errorCode = ErrorCode.getErrorCode(code);
    }

    public int getCode() {
        return code;
    }

    public LibException(String message) {
        super(message);
    }

    public LibException(String message, Throwable cause) {
        super(message, cause);
    }

}

    通过枚举和自定义异常的结合,便能在程序中动态的根据错误码反馈给上层调用者友好的异常信息。测试:

public class Test {
    public static void chenbenbuyi(int result) throws LibException {
        if(result>=0&&result<=4)throw new LibException(result);
        System.out.println("result: "+result);
    }

    public static void main(String[] args) {
        try {
            chenbenbuyi(3);
        } catch (LibException e) {
                System.err.println("错误码:"+e.getCode()+" 错误信息:"+e.getErrorCode().getMsg());
        }
    }
}

  友好输出反馈:

 

posted on 2019-01-10 09:18  陈本布衣  阅读(462)  评论(0编辑  收藏  举报
****************************************** 页脚Html代码 ******************************************