java之异常处理

异常这块,分为两块来讲,第一个是面试最喜欢问的,第二个是工作中应当注意的

Unchecked Exception:未经核查的异常
a. 指的是程序的瑕疵或逻辑错误,并且在运行时无法恢复。
b. 包括Error与RuntimeException及其子类,如:OutOfMemoryError, UndeclaredThrowableException, IllegalArgumentException, IllegalMonitorStateException, NullPointerException, IllegalStateException, IndexOutOfBoundsException等。
c. 语法上不需要声明抛出异常。

Checked Exception:检查异常
a. 代表程序不能直接控制的无效外界情况(如用户输入,数据库问题,网络异常,文件丢失等)
b. 除了Error和RuntimeException及其子类之外,如:ClassNotFoundException, NamingException, ServletException, SQLException, IOException等。
c. 需要try catch处理或throws声明抛出异常。

首先讲下面试最喜欢问的几个问题
1、介绍下异常体系
2、你在工作中都是怎么定义异常的
3、你为什么要定义那种类型的异常

Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类。
    在Java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception。

异常体系 最直接的就是看这张图


后面所有的问题都是围绕着这张图来的

java.lang.Throwable 是所有异常类的根类

Error是无法处理的异常,比如OutOfMemoryError,一般发生这种异常,JVM会选择终止程序。因此我们编写程序时不需要关心这类异常。
Exception 是checked (java 编译器必须要求 catch),大概指一类可以预知的,当发生异常后知道如何处理的异常。

RuntimeException 是属于unchecked (java 编译器允许不catch)表示一类 未知的不确定的只有在运行时才会出现的异常。
工作中都是自定义什么样的异常,当然是运行期异常,继承RuntimeException的异常,为什么是unchecked异常而不是checked异常
可能你们都没想过这个问题,只是看大家怎么做我就怎么做呗。
其实远远没有那么简单
首先要明白为什么java要弄出这两种异常
        之所以区分 checked/unchecked exception,JAVA的设计思想是区分从类/方法设计者角度来看两种不同的异常
一种是设计者认为这个方法在使用过程中使用者能够处理的异常,这些往往作为checked exception。比如一个IO系统的设计者会认为诸如物理文件不存在或者介质无法读取等异常时很可能发生,而使用者完全可能捕获这个异常,通过让用户 重新输入文件名等方式重新进行这个操作,也就是说,这是一个可恢复的操作。所以我会在诸如 read()/write()等操作中throw 一个 IOException(checked exception)。 
        第二种是设计者认为使用者不能够处理的异常,比如我写一个函数要求传入的参数是个正数,那么当我发现使用者传 了个负数进来时,合理的预期是程序中出bug了。如果我抛出一个异常描述这件事,即使我要求调用者捕获这个异常,他肯定也不知道该怎么办(总不能随便传一 个正数进来吧)。这时候我就会抛出一个IllegalArgumentException(uncheck exception),这里面的潜台词是:小子,我知道你也是帮人背黑锅的,处理不了这个,你还是交给你的领导(调用你的程序)去处理这个异常吧。
现在知道它们的本质区别了,再回到工作中来

        首先我们工作中定义的都是业务异常,而业务异常应该是什么类型异常呢,认真思考下,当然是使用者不能够处理的,否则难道你在某个地方抛出了个checked异常,你还希望调用者能够去处理下,可是业务异常就是出错了就不该继续走下去了。

        接着说我们在工作中碰到了这两种异常应该如何处理,我们面对checked exception(Exception)该怎么办
如果是main方法测试和junit测试遇到有抛出checkedexception(检查异常)的,原则上是需要你去处理的,要么捕获并打印,要么继续抛,不然编译不过去,我的选择是继续抛,反正最后会被jvm捕获并打印,你自己去捕获打印的话,代码量都多了,最后效果都是一样的。

如果是项目中,碰到此类异常,设计者认为是使用者能够处理的,但真的一定要去处理吗,这里我给出三种情况
1、使用者不能够明确的业务异常,建议继续抛出,比如IOException之类的异常,直接归类为系统异常,但谨记一定要被顶层调用者捕获掉,并打印。我看见很多人喜欢吞了它,下面会讲具体案例。

2、使用者能够明确的业务异常,建议捕获掉,先封装成业务异常,比如SQLException,封装成业务异常BizException,如{code:11111,msg:调用SQL出错},那为什么要这么做呢,原因是某些异常不能随意污染 上层调用代码,需要统一封装成业务异常,继续再抛出去。
3、使用者能够处理的异常,不应该影响后续流程,我们应该只是打印下异常信息(建议使用log.warn),接着添加发生异常后如何执行的代码(catch中),仅此而已,保证后面的代码继续执行,对于顶层【调用者】,应该就是当做该异常从来没有发生过,它也无需知道这种能被业务层自己处理的异常,而我们开发者只需在日志打印中对该处理有打印信息即可,如下面的代码。

面对unchecked exception(RuntimeException)又该怎么办
1、如果是main方法测试和junit测试遇到有抛出uncheckedexception(非检查异常)的一概不理,我们可以对unchecked异常不闻不顾,反正会被jvm捕获并打印出来,事实上我们基本都是这么做的,你真对抛出unchecked的方法进行try catch只为e.printStackTrace(),倒是觉得没事找事了,大可以什么都不管,jvm肯定能捕获到,并显示在你的console控制台。


       如果是项目代码,遇到了此类异常怎么办,还是不捕获吗,或者像某些人说的又没需要让我捕获,干嘛要捕获它,就让最终调用者,比如controller、action等来捕获并去打印,不就好了,那我反问一句,一个稍微复杂的业务流程里,unchecked exception(非检查异常)不说会碰到10几个吧,几个总有吧,你是要最终一层层的catch捕获吗,如果你漏了某个,那我非常遗憾的告诉你,如果正好发生了你遗漏的异常,整个日志文件里都不会有出现问题的异常信息的打印(虽然开发的时候jvm还是会给你打印在console控制台),直接就被你吞了,日后排错够你喝一壶;








  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值