https://www.dubby.cn/detail.html?id=9033

本篇文章主要给大家介绍一些众所周知的异常处理原则,但是也有部分鲜为人知,但也很有用的原则,希望能引发各位对异常处理的思考,以及在开发过程中,写出更优美的代码。

1.异常介绍

大致可以把异常分成三种情况下的异常(不正常情况):

  1. 代码错误引发的异常:比如数组越界,空指针等。
  2. 客户端错误调用引发的异常:比如用户名最长只允许32,客户端传了100;方法参数不能为空,客户端传了空等。
  3. 资源错误引发的异常:比如网络错误,硬盘故障,文件被删等。

2.Java中的异常介绍

无图言屌,下面就给出异常的继承关系图:

主要说说这几个概念:

  • Checked exceptions:这种异常在代码层面必须要捕获或者在签名处申明这个异常。这种异常是Java强制你必须捕获,因为这些一般一般是不可避免的,比如:网络,文件系统等不可控因素。
  • Unchecked exceptions:这种异常不会强制捕获或者在签名处申明。这类异常一般是由于代码问题产生的,比如:数组越界,空指针等。
  • Errors:这类错误,一般是在软件层面不可恢复的。比如:OutOfMemoryErrorLinkageError, 还有StackOverflowError。这种错误一般会是的程序(或者程序的一部分)不可用。针对这类错误,一定要有一个良好的日志习惯,不然很难定位。

3.自定义异常

一般我们想要自定义异常的目的都是为了让异常信息更丰富,比如:输入名称不合法,我们可能希望有一个UsernameInvalidException。本人在代码中曾经这么干过,一个类似的用法,好处很明显,在我们的内部监控系统中,对异常统计界面可以很清晰的反映出是什么问题,但是也带来一个问题,那就是异常数量很多。

在这里我先摆几个大师的意见吧:

  • 不要使用自定义异常:
    Java已经给我们提供了很多很多异常,尽量复用这些异常,好处有:减少我们的代码量,也就减少了维护的成本和精力,不至于让代码中出现很多只用过一次或几次的异常,最后异常数量爆炸(这就是我遇到的);使用通用异常,也可以减少别人阅读我们的代码,使用我们的接口时,更轻松,毕竟多一个类我们就需要理解这个类存在的意义。这里给几个经常可以用到的异常:
    1. IllegalStateException
    2. UnsupportedOperationException
    3. IllegalArgumentException
    4. NoSuchElementException
    5. NullPointerException
  • 如果不得不自定义异常,那就写个通用异常:
    如果自己不得不写的话,那就写的详细一下,不要只有个String来传达信息,那完全可以用通用的异常来替代,给个包含详细信息的例子:
  1. public class OutOfRangeException
  2. extends IllegalArgumentException {
  3. private final long value, min, max;
  4. public OutOfRangeException(long value, long min, long max) {
  5. super("Value " + value + " out of range " +
  6. "[" + min + ".." + max + "]");
  7. this.value = value;
  8. this.min = min;
  9. this.max = max;
  10. }
  11. public long getValue() {
  12. return value;
  13. }
  14. public long getMin() {
  15. return min;
  16. }
  17. public long getMax() {
  18. return max;
  19. }
  20. }

4.几个建议

1)不要生吞异常

  1. catch (NoSuchMethodException e) {
  2. return null;
  3. }

这样做会让这个异常信息永远的丢失,你将无法知道这个异常的原因,怎么去解决这个异常,甚至你不知道有这个异常的存在。

2)申明具体的异常

  1. public void foo() throws Exception { //不正确的做法
  2. }

这样除了告诉调用方我可能会有异常之外没有任何其他信息,而事实是我们本可以提供更具体的信息,建议这样做:

  1. public void foo() throws SpecificException1, SpecificException2 { //正确的做法
  2. }

3)尽可能的捕获具体异常

  1. try {
  2. someMethod();
  3. } catch (Exception e) {
  4. LOGGER.error("method has failed", e);
  5. }

这么做的问题是,如果你调用的方法中多了一个新的异常,他本来的目的是希望你处理这个新的异常,可是因为你在这里捕获了所有的异常,你可能会忽略这个提醒,而忘记捕获。

4)永远不要捕获Throwable

这样会捕获本来不该有我们来处理的错误,包括一些我们的代码无法处理的错误。

5)不要丢失异常信息

  1. catch (NoSuchMethodException e) {
  2. throw new MyServiceException("Some information"); //不正确
  3. }

这样做会完全丢失异常信息。

  1. catch (NoSuchMethodException e) {
  2. throw new MyServiceException("Some information: " + e.getMessage()); //不正确
  3. }

这种做法会丢失堆栈信息,建议:

  1. catch (NoSuchMethodException e) {
  2. throw new MyServiceException("Some information: " , e); //正确
  3. }

6)日志和上抛不可兼得

  1. catch (NoSuchMethodException e) {
  2. LOGGER.error("Some information", e);
  3. throw e;
  4. }

这样会导致一个问题,就是一个异常会有多份日志,因为上层可能也会记一次日志。所以要么上抛,要么记日志,不要都做。

7)不要在finally里抛异常

  1. try {
  2. someMethod(); //Throws exceptionOne
  3. } finally {
  4. cleanUp(); //If finally also threw any exception the exceptionOne will be lost forever
  5. }

这样的问题是,如果finally里也抛异常,就会导致真正的异常信息丢失,你只会收到finally里抛的异常。

8)不要为了捕获而捕获

  1. catch (NoSuchMethodException e) {
  2. throw e; //Avoid this as it doesn't help anything
  3. }

这段代码没有任何有意义,你可以直接上抛。

9)不要使用printStackTrace()或类似的语句

这种输出没有任何意义,而且不确定输出路径,对定位问题没有帮助。

10)不一定要catch

  1. try {
  2. someMethod(); //Method 2
  3. } finally {
  4. cleanUp(); //do cleanup here
  5. }

如果你只是想要finally来做善后,那就只用它就可以了,不要用catch。

11)“Throw early catch late”

这句话我不想翻译,因为我希望你能看到这句话,以后你也会见到这句话的。Throw early catch late。在底层抛异常,在信息足够的时候来捕获并处理。

12)记得用finall善后

比如数据库连接,一定要用finally关闭连接。当然你也可以用try-with-resource的方式。

13)上抛信息明确的异常

如果这个方法是解析文件,那么FileNotFoundException就比NullPointException更明确。

14)永远不要使用异常来做流程控制

  1. public void useExceptionsForFlowControl() {
  2. try {
  3. while (true) {
  4. increaseCount();
  5. }
  6. } catch (MaximumCountReachedException ex) {
  7. }
  8. //Continue execution
  9. }
  10. public void increaseCount()
  11. throws MaximumCountReachedException {
  12. if (count >= 5000)
  13. throw new MaximumCountReachedException();
  14. }

算我求你了,不要这么干!

15)尽早校验输入

很多异常都是由不合法的输入引起的,所以尽可能早的校验输入。

16)一条信息打印异常

  1. LOGGER.debug("Using cache sector A");
  2. LOGGER.debug("Using retry sector B");

何必呢?而且这样也容易误导其他人,建议:

  1. LOGGER.debug("Using cache sector A, using retry sector B");

17)让你的异常信息更充实

包括堆栈和其他提示信息。

18)如果线程被interrupted一定要结束线程

  1. while (true) {
  2. try {
  3. Thread.sleep(100000);
  4. } catch (InterruptedException e) {} //Don't do this
  5. doSomethingCool();
  6. }

这段代码很cool,但是一般会interrupt线程,要么是超时了,要么是线程池被关闭了,所以你应该尽可能的去结束线程。

19)使用模板来减少重复的try-catch代码

  1. class DBUtil{
  2. public static void closeConnection(Connection conn){
  3. try{
  4. conn.close();
  5. } catch(Exception ex){
  6. //Log Exception - Cannot close connection
  7. }
  8. }
  9. }

使用这个来减少每次都try一遍。

20)文档中加上异常说明

  1. /**
  2. * This method does something extremely useful ...
  3. *
  4. * @param input
  5. * @throws MyBusinessException if ... happens
  6. */
  7. public void doSomething(String input) throws MyBusinessException { ... }

前人种树后人乘凉,你可能也可以乘凉。

Java Exception最佳实践(转)的更多相关文章

  1. Atitit.嵌入式web 服务器 java android最佳实践

    Atitit.嵌入式web 服务器 java android最佳实践 1. Android4.4.21 2. 自己的webserver1 3. CyberHTTP for Java  cybergar ...

  2. Java异常处理最佳实践

    总结一些Java异常的处理原则 Java异常处理最佳实践 不要忘记关闭资源 在finally里关闭资源 public void readFile() { FileInputStream fileInp ...

  3. paip.myeclipse7 java webservice 最佳实践o228

    paip.myeclipse7  java webservice 最佳实践o228 java的ws实现方案:jax-ws>>xfire ws的测试工具  webservice测试调用工具W ...

  4. 10个精妙的Java编码最佳实践

    这是一个比Josh Bloch的Effective Java规则更精妙的10条Java编码实践的列表.和Josh Bloch的列表容易学习并且关注日常情况相比,这个列表将包含涉及API/SPI设计中不 ...

  5. 最重要的 Java EE 最佳实践

    參考:IBM WebSphere 开发人员技术期刊: 最重要的 Java EE 最佳实践 IBM WebSphere 开发人员技术期刊: 最重要的 Java EE 最佳实践 2004 年 IBM® W ...

  6. 你知道吗?10个精妙的 Java 编码最佳实践

    这是一个比Josh Bloch的Effective Java规则更精妙的10条Java编码实践的列表.和Josh Bloch的列表容易学习并且关注日常情况相比,这个列表将包含涉及API/SPI设计中不 ...

  7. Java异常处理最佳实践及陷阱防范

    前言 不管在我们的工作还是生活中,总会出现各种“错误”,各种突发的“异常”.无论我们做了多少准备,多少测试,这些异常总会在某个时间点出现,如果处理不当或是不及时,往往还会导致其他新的问题出现.所以我们 ...

  8. Java开发最佳实践(二) ——《Java开发手册》之"异常处理、MySQL 数据库"

    二.异常日志 (一) 异常处理 (二) 日志规约 三.单元测试 四.安全规约 五.MySQL数据库 (一) 建表规约 (二) 索引规约 (三) SQL语句 (四) ORM映射 六.工程结构 七.设计规 ...

  9. Java开发最佳实践(一) ——《Java开发手册》之"编程规约"

    Java开发手册版本更新说明 专有名词解释 一. 编程规约 (一) 命名风格 (二) 常量定义 (三) 代码格式 (四) OOP 规约 (五) 集合处理 (六) 并发处理 (七) 控制语句 (八) 注 ...

  10. .NET Core学习笔记(7)——Exception最佳实践

    1.为什么不要给每个方法都写try catch 为每个方法都编写try catch是错误的做法,理由如下: a.重复嵌套的try catch是无用的,多余的. 这一点非常容易理解,下面的示例代码中,O ...

随机推荐

  1. MySQL中如何定位阻塞语句

    数据库中阻塞语句的查询和分析 前言 MySQL 1.使用 show processlist 查询正在运行的进程 2.使用 INNODB_TRX 查询当前运行的事务 3.使用 INNODB_LOCKS ...

  2. 路由分发admin源码

    1. 不使用include方法 1.表象 另一种路由编写方式,不用使用include 引出namespace概念 可以看到如果使用include方法,后面可带上一个参数赋值给namespace 在无n ...

  3. Kafka主从模式和故障切换

    Kafka集群有主从模式吗? Kafka集群实际上并没有严格意义上的主从模式.Kafka的设计是基于分布式的,每个Topic都会切分为多个Partition,每个Partition都有一个Leader ...

  4. 手机免root安装最新青龙面板(非Alpine term | Zero term软件)

    使用软件:Termux 可以用于任何支持qemu虚拟机的环境.APP 制作了基本的系统环境.开发环境和青龙面板环境.多个虚拟机,按需求下载 官方网站:https://api.wer.plus 群:10 ...

  5. Oracle11gR2单实例的安装与部署

    1   安装目标与规划 交易系统1台HP DL580 G9服务器将安装Oracle11gR2 . 1.1  安装介质版本 主机名 his1 IP地址 192.168.40.102(非生产环境ip) O ...

  6. Kitex微服务开发实践(ETCD服务注册)

    服务注册通常用于分布式系统或微服务架构中,是一种用于管理和发现这些分布式服务的机制.它的目标是让服务能够动态地找到其他服务,并能够与其进行通信,而无需显式地配置其位置信息 本文简单讲述使用etcd进行 ...

  7. ctypes使用浅谈

    什么是ctypes: ctypes 是 Python 的一个标准库,用于与 C 语言进行交互.它提供了一组工具和函数,可以方便地调用动态链接库(DLL)或共享对象(SO)中的 C 函数,并处理 C 数 ...

  8. 智能AI 的应用场景

    小凡智能AI是一款基于人工智能技术开发的助软件,能够帮助用户解决各种各样的问题,提高工作效率和生活质量.它的应用范围广泛,涵盖了工作.学习.健康等多个方面,为用户提供了全方位的服务支持. 在工作方面, ...

  9. IDEFICS 简介: 最先进视觉语言模型的开源复现

    引言 Code Llama 是为代码类任务而生的一组最先进的.开放的 Llama 2 模型,我们很高兴能将其集成入 Hugging Face 生态系统!Code Llama 使用与 Llama 2 相 ...

  10. 文心一言 VS 讯飞星火 VS chatgpt (89)-- 算法导论8.3 2题

    二.用go语言,下面的排序算法中哪些是稳定的:插入排序.归并排序.堆排序和快速排序?给出一个能使任何排序算法都稳定的方法.你所给出的方法带来的额外时间和空间开销是多少? 文心一言: 在Go语言中,以下 ...