Java异常最佳实践笔记

58 篇文章 0 订阅

Java异常最佳实践笔记

引用

《如何善用Java异常》
https://juejin.im/post/5bacd8975188255c69780e7b

笔记

  • Java中的异常分为两种:
    1. 无法捕获处理的系统级别Error.
    2. 可以被认为处理的检测异常Exception.
    • 重点是他们都继承了Throwable接口
  • 其中需要我们处理的只有Exception的子类。Exception的子类异常都是【可以】被我们的捕获处理的。可以被我们处理的意思,即可不处理,也可以处理。(即,可以处理,但没必要)
  • 其中Exception的子类RuntimeException则允许我们不对他处理,它是一种特殊Exception,特殊之处在于允许我们不对它做捕获处理, 这种异常叫运行时异常,意思就是运行期间才会产生的,理论上大部分异常都是在运行期间才会产生了。也就是说大部分异常我们都可以置之不理,因为他是运行期间才会产生的,运行期间发现的意外大部分都是我们无法考虑到的(就像我们的生活,“意外”总比“预料”多。)
  • 异常最佳实践:
    • 能用runtimeExcepiton,用runtimeException。把异常抛给运行时处理,毕竟大部分的异常都是无法认为处理的,直接tryCatch也无法处理的异常,只能抛给运行时了。
    • 能tryCatch的异常就不算异常,因为既然能tryCatch证明你能处理它,比如IOException,你TryCatch了这个IO异常,就表示有默认值返回(比如Null),如果无法返回默认值,请tryCatch后抛出运行时异常。
    • 关于异常的日志问题,无论什么异常处理最好都logger打印一下日志,并且写明原因,如果有必要最好,Logger.info(“错误信息”,ex); 或者 log.XXX(Object obj,Thowable e) 的形式打印一下日志,这样就可以顺带打印出exceptionStackTrace.
    • 其次就是不要使用ex.printStacktrace(),因为这是不好的习惯,请用log.XXX(Object obj,Thowable e) 的形式的代替他
      • 理由:1. 你很难确定它会打印到哪个文件,让logger框架管理比较好。2.它有可能打印给终端用户页面一堆乱七八糟的信息。
    • 定义一个全局的异常捕捉器(spring的全局异常捕捉器ErrorController),对所有错误异常进行解析处理成页面返回给终端用户页面。具体怎么实现呢?查一下《spring全局异常处理》相关资料即可。

关于异常比较好的知识点:

在这里插入图片描述

  • Java7与异常Java7对异常做了两个改进。第一个是try-with-resources,第二个是catch多个异常。
  • try-with-resources主要是针对IOException基本都是需要关闭资源的,所以用try-with-resources来关闭资源,可以让代码更好看。

不使用try-with-resources,我们在使用io等资源对象时,通常是这样写的:String getReadLine() throws IOException {
    BufferedReader br = new BufferedReader(fileReader);
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }
}
复制代码使用try-with-recources的写法:String getReadLine() throws IOException {
    try (BufferedReader br = new BufferedReader(fileReader)) {
        return br.readLine();
    }
}

显然,编绎器自动在try-with-resources后面增加了判断对象是否为null,如果不为null,则调用close()函数的的字节码。

只有实现了java.lang.AutoCloseable接口,或者java.io.Closable(实际上继随自java.lang.AutoCloseable)接口的对象,才会自动调用其close()函数。

有点不同的是java.io.Closable要求一实现者保证close函数可以被重复调用。而AutoCloseable的close()函数则不要求是幂等的。
具体可以参考Javadoc。

但是,需要注意的是try-with-resources会出现异常覆盖的问题,也就是说catch块抛出的异常可能会被调用close()方法时抛出的异常覆盖掉。我们会在下面的小节讲到异常覆盖。

多异常捕捉直接上代码:public static void main(String[] args) {
    try {
        int a = Integer.parseInt(args[0]);
        int b = Integer.parseInt(args[1]);
        int c = a / b;
        System.out.println("result is:" + c);
    } catch (IndexOutOfBoundsException | NumberFormatException | ArithmeticException ie) {
        System.out.println("发生了以上三个异常之一。");
        ie.getMessage();
        // 捕捉多异常时,异常变量默认有final修饰,
        // 所以下面代码有错:
        // ie = new ArithmeticException("test");
    }
}

作者:xy的技术圈
链接:https://juejin.im/post/5bacd8975188255c69780e7b
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
什么是异常覆盖正如我们前面提到的,在finally块调用资源的close()方法时,是有可能抛出异常的。与此同时我们可能在catch块抛出了另一个异常。那么catch块抛出的异常就会被finally块的异常“吃掉”。看看这段代码,调用test()方法会输出什么?void test() {
    try {
        overrideException();
    } catch (Exception e) {
        System.out.println(e.getMessage());
    }
}

void overrideException() throws Exception {
    try {
        throw new Exception("A");
    } catch (Exception e) {
        throw new Exception("B");
    } finally {
        throw new Exception("C");
    }
}
复制代码会输出C。可以看到,在catch块的B被吃掉了。JDK提供了Suppressed的两个方法来解决这个问题:// 调用test会输出:// C// Avoid test() {
    try {
        overrideException();
    } catch (Exception e) {
        System.out.println(e.getMessage());
        Arrays.stream(e.getSuppressed())
                .map(Throwable::getMessage)
                .forEach(System.out::println);
    }
}

void overrideException() throws Exception {
    Exception catchException = null;
    try {
        throw new Exception("A");
    } catch (Exception e) {
        catchException = e;
    } finally {
        Exception exception = new Exception("C");
        exception.addSuppressed(catchException);
        throw exception;
    }
}
复制代码异常链你可以在抛出一个新异常的时候,使用initCause方法,指出这个异常是由哪个异常导致的,最终形成一条异常链。详情请查阅公众号之前的关于异常链的文章。

作者:xy的技术圈
链接:https://juejin.im/post/5bacd8975188255c69780e7b
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值