Java异常捕获的设计原则

每个软件都可能遇到异常,所以从设计阶段就要考虑异常处理的问题,纳为业务流程的一部分。

异常是需要妥善处理的,但是处理的前提是发现异常,而发现异常的前提的对异常有清楚的认识,我们要先认识到程序中都有什么样的异常(定义异常),然后在程序结构中检测和抛出异常(捕获异常),最后用恰当的业务流程去分别处理(处理异常)

所以,发现和处理异常的过程可以简单归纳为定义->发现->处理的过程,也就是定义异常-->捕捉异常->处理异常。

一、定义异常

要定义异常,就要看看程序都可能有哪些异常,如何去为这些异常分类。

异常当前不只一种,只有一种异常是不能满足业务流程需要的。

例如在线登录失败这种异常,只抛出一个“登录失败”是无法准确处理的,失败是因为网络连接失败?还是用户名密码错误?这两种错误类型,要分别去走不同的业务流程,一个要检查网络,一个要检查用户名密码,只有定义成不同的异常,才能根据实际情况去引导用户分别操作。

1.Throwable

在Java中,异常的基类是Throwable,它只引用了Serializable这个可序列化接口,基于Throwable,还有Exception、RuntimeException和Error这三个类,这几个类之间的关系如下:

异常处理类之间的关系

我们看到从大的分支上来看,分为Error和Exception两大类,我们先看看这两类有什么区别。

2.Error和Exception

我们看一组对比:

Error                                   Exception

check                                  uncheck(运行时)

主要在编译时提示               运行时提示

不建议捕获                          建议捕获

Error错误,主要在开发时起检查作用(check),编译器在编译时,根据已知可能存在的异常,提示开发者,例如,把一个String值直接赋给int对象,编译器就会提示Error了。

Exception异常,是编译器检查不出来的(uncheck),是在软件运行时才会发现的异常,也就是运行时异常(RuntimeException),例如,做一个3/0的运算,这是个算术错误,但是编译器在编译阶段看不出错误,只有在运行阶段才能发现异常。

Error和Exception这两种异常,其实都是可以用try catch捕获的,写catch(Error e)/catch(Exception e)就可以捕获,但是一般不建议捕获Error错误,这是为什么呢?

因为分工不同,先看Exception,这是运行阶段可能出现的异常,一般在某些特殊逻辑分支或参数下,才可能出现,开发者也应该对这种逻辑进行处理,所以建议捕获异常进行处理;

但是Error是不建议捕获的,前面说了,Error不是运行阶段可能出现的错误,他本身就代表程序逻辑有硬伤,或者运行环境不正确,在这种情况下,即便是捕获了异常,程序也没有办法继续执行,所以建议不捕获。

我们找两个例子,ClassNotFoundException和NoClassDefFoundError,这两个看起来都是找不到类导致的异常,但是一个是Exceptioin异常,一个是Error错误,我们对比一下,就能理解Error和Exception的区别了。

ClassNotFoundException,是个Exception异常,一般在反射时遇到,是动态加载时报错的,动态加载是开发者故意设计的业务逻辑,本身就有失败的可能,所有建议捕获异常。

NoClassDefFoundError,是个Error错误,这个错误发生时,在编译时都没有问题,但是运行时,JVM或者ClassLoader去加载某个类,发现这个类找不到了,就会报这个错误。这一般是运行环境的问题,例如缺少库文件什么的,这个错误与业务逻辑无关,是必须解决掉的错误,否则软件无法继续运行,所以不建议捕获异常。

3.异常子类

异常子类一般都是Exception的子类,Java提供了丰富的异常类,开发者也可以自定义异常类,异常类的作用就是描述什么出了错,和为什么出错,例如:IllegalArgumentException("filepath is null"),就抛出了一个参数错误的异常,而且说明了出错的原因是"filepath is null"。

在实际开发中,我们需要根据自己的业务场景,去选用或自定义异常类型,根据实际情况去抛出异常。

二、捕获异常

前面一直在说定义异常的问题,接下来我们要捕获到这些异常。在出现异常时,我们需要立即知道哪里出了异常,为什么会出异常,具体来说,就是定位到异常代码,并为异常分类,去定义这个异常的消息内容。

1.定位

Java可以比较容易地定位到异常代码,异常堆栈提供了导致异常的方法调用链,能精确定位到类名,方法,代码行。

2.分类

分类就需要一定的设计经验了,一方面要提前做好异常定义,另一方面要在代码中准确抛出异常

例如:在读取文件时,把文件地址作为参数,如果输入一个空的文件地址,Java默认只会报一个NullPointerException空指针异常,也没有异常消息,这种宽泛的分类下,我们只知道这里出现了异常,却不知道为什么会异常,后面的异常处理就没办法做。

这种情况下,我们为了能精准地处理空文件地址的问题,就需要自己去判断文件名是否为空,如果为空,则抛出一个IllegalArgumentException,并自定义一个"filepath is null"的异常消息传出来,这样后面处理时,就可以在这种情况下提示用户“请输入文件地址”,而不是简单粗暴地报一句“出错啦”了事。

3.捕获

异常捕获是需要融入到代码逻辑中的,首先要预见可能的异常,然后定义异常及其异常消息,最后才能在代码段中捕获到相应的异常。

4.抛出

有时候,我们需要主动抛出异常,比如我们不希望用户调用某些函数,或在某些逻辑分支中提前判断并抛出异常,我们可以主动在代码里throw一些异常,比如throw methodErr("visiting this method is not allowed");

三、处理异常

我们捕获异常,最终都是为了走恰当的业务流程,去处理异常。

Java有两种处理异常的方式,一是自己捕获,用try catch去捕捉异常,在catch代码里处理;另一种是让调用者捕获,用throw抛出异常,通知调用者去处理。

这两种处理方式不是随便选择的,要看具体的业务,异常应该马上捕获,但不一定要马上处理

例如:服务器查询数据库时,业务层查询数据,会调用数据访问层,这时如果数据库连接失败就会出现异常,这个异常如果在数据层自己捕获到,就仅限于数据层知道了,业务层根本不知道出了异常,会误以为数据库中没有这种数据。这时正确的做法应该是抛出异常,用throw向业务层抛出异常,让业务层自己去处理,决定是重试连接,还是告知用户。

异常的提示,是与业务相关的,如果需要用户走不同的逻辑分支,就需要设计相关的界面和提示;如果需要反馈给开发者,就需要记录日志并上传到服务器。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容