美文网首页
异常的处理

异常的处理

作者: JBryan | 来源:发表于2020-03-04 16:15 被阅读0次
    1.Java的异常

    Java的异常是class,它的继承关系如下:


    异常.jpg

    从继承关系可知:Throwable是异常体系的根,它继承自Object。Throwable有两个体系:Error和Exception,Error表示严重的错误,程序对此一般无能为力,例如:
    OutOfMemoryError:内存耗尽
    NoClassDefFoundError:无法加载某个Class
    StackOverflowError:栈溢出
    而Exception则是运行时的错误,它可以被捕获并处理。Exception又分为两大类:
    RuntimeException以及它的子类;
    非RuntimeException(包括IOException、ReflectiveOperationException等等)
    Java规定:
    必须捕获的异常,包括Exception及其子类,但不包括RuntimeException及其子类,这种类型的异常称为Checked Exception。
    不需要捕获的异常,包括Error及其子类,RuntimeException及其子类。

    2.捕获异常

    在Java中,凡是可能抛出异常的语句,都可以用try … catch捕获。把可能发生异常的语句放在try { … }中,然后使用catch捕获对应的Exception及其子类。
    可以使用多个catch语句,每个catch分别捕获对应的Exception及其子类。JVM在捕获到异常后,会从上到下匹配catch语句,匹配到某个catch后,执行catch代码块,然后不再继续匹配。
    简单地说就是:多个catch语句只有一个能被执行。例如:

    public static void main(String[] args) {
        try {
            process1();
            process2();
            process3();
        } catch (IOException e) {
            System.out.println(e);
        } catch (NumberFormatException e) {
            System.out.println(e);
        }
    }
    

    存在多个catch的时候,catch的顺序非常重要:子类必须写在前面。例如:

    public static void main(String[] args) {
        try {
            process1();
            process2();
            process3();
        } catch (IOException e) {
            System.out.println("IO error");
        } catch (UnsupportedEncodingException e) { // 永远捕获不到
            System.out.println("Bad encoding");
        }
    }
    

    对于上面的代码,UnsupportedEncodingException异常是永远捕获不到的,因为它是IOException的子类。当抛出UnsupportedEncodingException异常时,会被catch (IOException e) { … }捕获并执行。
    finally语句块保证有无错误都会执行。
    finally语句不是必须的,可写可不写;
    finally总是最后执行。如果没有发生异常,就正常执行try { … }语句块,然后执行finally。如果发生了异常,就中断执行try { … }语句块,然后跳转执行匹配的catch语句块,最后执行finally。

    public static void main(String[] args) {
        try {
            process1();
        } catch (IOException e) {
            System.out.println("IO error");
        } finally {
            System.out.println("END");
        }
    }
    
    3.抛出异常

    当发生错误时,例如,用户输入了非法的字符,我们就可以抛出异常。

    void process2(String s) {
        if (s==null) {
            throw new NullPointerException();
        }
    }
    

    在catch中抛出异常,不会影响finally的执行。JVM会先执行finally,然后抛出异常。
    如果一个方法捕获了某个异常后,又在catch子句中抛出新的异常,就相当于把抛出的异常类型“转换”了:

    void process1(String s) {
        try {
            process2();
        } catch (NullPointerException e) {
            throw new IllegalArgumentException();
        }
    }
    void process2(String s) {
        if (s==null) {
            throw new NullPointerException();
        }
    }
    

    当process2()抛出NullPointerException后,被process1()捕获,然后抛出IllegalArgumentException()。打印出的异常栈类似:

    java.lang.IllegalArgumentException
        at Main.process1(Main.java:15)
        at Main.main(Main.java:5)
    

    这说明新的异常丢失了原始异常信息,我们已经看不到原始异常NullPointerException的信息了。
    为了能追踪到完整的异常栈,在构造异常的时候,把原始的Exception实例传进去,新的Exception就可以持有原始Exception信息。对上述代码改进如下:

    void process1(String s) {
        try {
            process2();
        } catch (NullPointerException e) {
            throw new IllegalArgumentException(e);
        }
    }
    void process2(String s) {
        if (s==null) {
            throw new NullPointerException();
        }
    }
    

    运行上述代码,打印出的异常栈类似:

    java.lang.IllegalArgumentException: java.lang.NullPointerException
        at Main.process1(Main.java:15)
        at Main.main(Main.java:5)
    Caused by: java.lang.NullPointerException
        at Main.process2(Main.java:20)
        at Main.process1(Main.java:13)
    
    4.自定义异常

    当我们在代码中需要抛出异常时,尽量使用JDK已定义的异常类型。例如,参数检查不合法,应该抛出IllegalArgumentException:

    static void process1(int age) {
        if (age <= 0) {
            throw new IllegalArgumentException();
        }
    }
    

    在一个大型项目中,可以自定义新的异常类型,但是,保持一个合理的异常继承体系是非常重要的。一个常见的做法是自定义一个BaseException作为“根异常”,然后,派生出各种业务类型的异常。BaseException需要从一个适合的Exception派生,通常建议从RuntimeException派生:

    public class BaseException extends RuntimeException {
    }
    

    其他业务类型的异常就可以从BaseException派生:

    public class UserNotFoundException extends BaseException {
    }
    public class LoginFailedException extends BaseException {
    }
    

    自定义的BaseException应该提供多个构造方法:

    public class BaseException extends RuntimeException {
        public BaseException() {
            super();
        }
        public BaseException(String message, Throwable cause) {
            super(message, cause);
        }
        public BaseException(String message) {
            super(message);
        }
        public BaseException(Throwable cause) {
            super(cause);
        }
    }
    

    相关文章

      网友评论

          本文标题:异常的处理

          本文链接:https://www.haomeiwen.com/subject/geavlhtx.html