`

关于Java异常抛出和处理的思考

    博客分类:
  • java
阅读更多
看过不少关于java异常处理的争论,也在不同项目里见到过异常处理不善,造成的灾祸。
以下谈谈一些个人的感受。
一、异常处理的现状
印象里接触过的项目,在异常处理上都觉得欠缺妥当, 没有从全局上来考虑。于是大量的代码中可以看到
try{
...
}catch(Exception ex){
  ex.printStackTrace();
}
于是异常就被吃掉了, 程序还会若无其事的继续进行。
从各种情况来看,程序员其实很烦恼异常处理,因此碰到要强制捕获的时候,要么就throws,要买就catch(Exception ex)全部抓掉,再一句话:  e.printStackTrace()。
抛出异常, 我看到很多程序员也不太喜欢,宁可用int返回值定义各类异常情况。

事实上,异常处理不当,对整个项目危害是很大的,可能造成程序结构和逻辑上都会混乱,常常会容易出错,健壮性不好。因此, 应该努力在项目架构确定的同时也确定对异常的统一约定,应该本着简洁、合理的基本原则。

二、异常的两种类型
非检查异常和已检查异常。
1)非检查异常,Throwable继承树的两个分支被编译器放宽了异常检查行为,允许不作捕获。java.lang.Error和 java.lang.RuntimeException的子类免于编译时检查,这就是未检查异常(unchecked exception)。
2)其他的编译器要求强制捕获的就属于已检查异常(checked exception)
其实要讨论异常处理的基本原则,就是要理解以上两种异常的不同特点,何种情况应该抛出何种异常。容易发现,jdk的很多方法抛出的异常都是checked exception,因为会强制要求我们捕获。

三、错误和意外
在谈论异常抛出的基本准则之前,有必要先看看抛出异常时可能面对的两类情况:错误和意外。
1)意外
假设一个银行支付的场景,有一个CheckingAccount 环节,检查客户的账户余额是否足够,如果发现余额不足,抛出了一个InsufficientFundsException,并且要终止支付动作。
那么这个余额不足就应当那个视为一个意外事件,正常情况下是可以完成支付的,现在余额不足要终止。很显然,对于意外事件,我们是可以预料到的,而且也有相应的处理措施,这里就是终止支付操作,并提示客户需要充值了。

2)错误
如果以上场景, 网线掉了呢?我们可能会接受到一个NetworkException,但显然我们无法通过程序来处理这个问题的。
这时我们将这个异常视为错误, 因为我们没法处理,也无法预期这类问题, 网络的问题,可能是网线掉了,也可能是网络设置不对等原因。

三、异常抛出的基本准则
看了以上两类异常情况,我们大概就能意识到,意外的情形我们应该使用checked exception;而错误情形,我们就应该用unchecked exception。
有个底线,就是问问自己,这个异常如果跑出去是否还有挽救的余地,如果可以则用checked exception;否则就unchecked exception。

像UserNotFoundException、NoAuthenticationException、NotEnoughMoneyException都可以归于checked exception,都代表着一个意外事件,有应对的策略。而IOException、SQLException都是不可预料、不可恢复的,应该用unchecked exception会合适一些。不过jdk的开发人员显然是偏爱checked exception,强类型的更加打眼,能明显看出可能出现的问题, 却不管你能不能搞定它。碰到这个情况,我们可以将checked Exception转换成unchecked Exception,这种做法也出现在了大量的开源框架中,一般都会有个异常转换器来做这个转换工作 。

四、异常处理的准则?
我总结了两条出来:
1)对于unchecked,既然是不可恢复的,那我们就不能及时处理,但我们可能还是需要最后去记录一下,然后给出一个“系统错误”之类的提示。那么就可以在应用程序的上层设置一个屏障专门处理这类异常。
2)对于checked,我们需要及时处理,如果发现无法处理就转化成unchecked再次抛出。

异常处理需要try...catch,如果有几类异常就要写好几个catch,因此很多程序员都比较排斥用异常表示意外和错误,他们采用方法返回值int,然后根据这个返回值switch来确认不同的异常情况和作处理。于是,我也思考了异常跟这种方式的优劣。
用方法的返回值代替异常,我们也能在jdk的代码中看到影子,比如String.indexOf就是返回-1表示找不到字串或者字符,IO类里面更是用-1表示是否流读取结束。
这时看起来还是很容易理解的, 而且不用异常也能减低一些开销。但也能发现一个问题,如果这个返回值不是int这类数字,或者说不是基本类型,那么就不好拿返回值表示异常了,当然还有void的情形更不可行。再想想,其实-1,-2,-3表示异常肯定还是需要定义一个常量类来表示,并取个具有意义的变量命会比较好。
这样我就发现这个方式应付不了大多数情形,而且可读性上也差点,定义好异常,直接throws和catch倒还方便。

五、log异常
出现了异常,我们可能需要log记录下来,因为这个异常有些特殊的业务含义,我们需要归档。
合理的设计应该是:
1)对于checked异常, 抛出的时候我们log一下;
2)Unchecked异常,在最上层的错误屏障log,记录下异常信息和堆栈。

总结一下,异常但并不可怕,关键是我们能认真的理解和分析它们。
分享到:
评论

相关推荐

    《Java程序设计案例教程》教学课件07异常处理.pptx

    02 了解Java异常体系结构,以及受检异常和未受检异常的区别。 03 掌握使用try-catch-finally语句块捕捉并处理异常。 05 掌握设计和使用用户自定义异常。 04 掌握使用throw语句抛出异常,以及使用throws语句声明方法...

    JAVA基础课程讲义

    异常的处理办法之三,手动抛出异常,throw子句 103 自定义异常 103 使用异常机制建议 104 总结 105 思考作业 105 上机作业 105 第五章 数组 106 数组概述和特点 106 创建数组和初始化 106 数组常见操作 108 数组的...

    Java异常的深入研究与分析

    切记:操千曲而后晓声,观千剑而后识器,所以我觉得没有大量的源码阅读经验,你很难知道什么时候需要自定义异常,什么时候需要抛出异常。  异常机制概述  异常机制是指当程序出现错误后,程序如何处理。具体来说...

    Java代码规范编码规约

    2)公共的方法或抽象类的方法,尽可能描述清楚:输入、输出、错误处理和返回码、以及可能抛出的异常。 3) 能够描述出业务的具体含义,使得读者能够快速了解代码背后的信息。 四、方法设计 1.【推荐】 方法的长度限制...

    面向对象技术与UML课件及源代码-by 南邮-陈杨

    9.3异常的向前抛出 9.3.1为什么要向前抛出 9.3.2如何向前抛出 9.4自定义异常 9.4.1为什么需要自定义异常 9.4.2如何自定义异常 9.5小结 第10章Java常用API 10.1数值运算 10.1.1用Math类实现数值运算 10.1.2...

    C++大学教程,一本适合初学者的入门教材(part2)

    13.8 再抛出异常 13.9 异常指定 13.10 处理意外异常 13.11 堆栈解退 13.12 构造函数、析构函数与异常处理 13.13 异常与继承 13.14 处理new故障 13.15 auto_ptr类与动态内存分配 13.16 标准库异常层次 小结 ...

    C++大学教程,一本适合初学者的入门教材(part1)

    13.8 再抛出异常 13.9 异常指定 13.10 处理意外异常 13.11 堆栈解退 13.12 构造函数、析构函数与异常处理 13.13 异常与继承 13.14 处理new故障 13.15 auto_ptr类与动态内存分配 13.16 标准库异常层次 小结 ...

    Java如何优雅的实现时间控制

    前言:需求是这样的,在与第三方对接过程中,对方提供了token进行时效性验证,过一段时间...虽然这种方式可以,但是存在一个隐患,如果在多线程环境下,线程很容易被interrupt,这样代码就会抛出异常,这样线程就会挂

    基于j2ee的ajax宝典

    3.6.3 异常抛出语句··················· 86 3.6.4 异常捕捉语句··················· 87 3.6.5 with语句········ 88 3.7 流程控制·················...

    C++大学教程

    1.9 Java、Internet与万维网--------------------------------------------7 1.10 其它高级语言------------------------------------------------------8 1.11 结构化编程-----------------------------------...

    测试培训教材

    软件测试的度量是测试管理必须仔细思考的问题。缺乏尺度会让测试失去平衡,缺乏标准会让测试工作难以衡量。 2、如何搭建测试管理平台? 首要问题是流程的规范化。 (1) 测试进入和退出标准。 (2) 协作流程。 (3...

    JavaScript高级教程

    2.5 原始值和引用值..............................................13 2.6 原始类型..............................................13 2.6.1 typeof 运算符..............................................14 ...

Global site tag (gtag.js) - Google Analytics