异常要怎么抛?
上一章,我们一起学习了打日志的点点滴滴,很多同学跟我反馈,自己好像从来没打对过日志,也有同学跟我吐槽,MD,最讨厌那些吞异常的SX。
今天,我们就来看看这个有意思的问题: 异常到底该怎么抛?
今天,我依然在地铁上与你分享,加班🐶,伤不起。﹏。
讲解异常之前,我们先看另外一个问题: http的状态码有哪些?
这个我相信大家都很熟悉了,我随便说几个:
200,成功
400,错误的请求
401,未认证
403,未授权
500,服务器内部错误
503,网关错误
嗯,知道这么几个就差不多了,其中,401和403,一个表示未认证,一个表示未授权,未认证可以理解为没有登录的意思,未授权可以理解为没有权限,有可能是没登录没有权限,也有可能是登录但是你就是没有权限,这不是本文的重点,仔细体会一下就好。
我们主要来看400和500这两个状态码,400表示错误的请求,500表示内部服务器错误,他们有什么本质的区别么?
用一句话来解释,一个表示因为客户端的参数不对导致服务器无法继续处理引起的错误,一个表示服务器内部的某些因素导致的错误,这里的某些因素可能是代码问题,数据库问题,远程调用问题,等等。
对于400错误,我们一般自己检查下请求参数就可以给用户友好的提示,比如,新增用户却没有填写用户名,我们直接提示用户名不能为空就好了。
对于500错误,它是服务器内部的错误,比如你的代码空指针了,数据库用户名这个字段长度不够,A调B,B却不通,等等,这种异常你怎么给用户提示呢?没法提示,不能直接把异常堆栈给用户吧(有没有中招😁)
好吧,这下真的用一句话来总结,400是用户的错误,500是程序员的错误,啊哈哈。
针对这两种错误呢,我们使用spring框架一般都会做统一的异常处理层。
比如说,我的新项目,我分别定义了两个异常类,BadRequestException和SeverErrorException,然后在spring异常层判断如果是BadRequestException我就直接返回msg,如果是SeverErrorException我就全部返回"内部服务器错误"。
本以为,大家都按我这个来用就好了,结果,转测之后,测试天天在群里喊,咋回事啊,怎么全都是"内部服务器错误",快点帮我查一下。
我,握了棵草,查看了几个人的代码之后,我发现,全部在乱用,被逼无奈之下,我让他们都改一下,然后每个人都问我一下,为什么不能用这个却要用那个,前面几个我还能耐心的给讲讲细节,后面我实在不耐烦了,最后,亮出了我的大招。
我在common中把ServerErrorException移到了与异常处理类同包下,并把其可见性改成了包包内可见,然后,对所有人说你们只能使用BadRequestException,ServerErrorException只能我在框架层使用,算是彻底解决了这个问题。
写了这么多,好像还没有讲到今天的主题: 异常怎么抛的问题。
其实,对于业务开发者,真正能使用到的就应该是只有对于客户端错误的检查自己手动抛出异常,其他的异常一律不需要关心,比如空指针异常,远程调用异常,数据库异常,你要相信,这些异常都会在框架层处理的很好。
不需要在你的代码起止加try catch!
不需要在你的代码起止加try catch!
不需要在你的代码起止加try catch!
当然,受检异常除外,什么是受检异常的,简单点讲,就是非运行时异常,比如,读取文件,有可能抛出FileNotExistException,这类异常需要你手动捕获异常,在编译期就需要try catch,但是,即使这样,你也应该保证你的try catch范围足够小,只包住那一个方法调用即可,并且,在catch中包装成你自己的运行时异常继续往外抛。
咦,这里就可能会出现开头说的吞异常的问题了,所以说try catch一定要按下面的格式写:
try {
} catch (XxxException e) {
throw new YourRuntimeException("xxx文件不存在",e);
}
注意,这里不需要打印日志,直接带上e往外抛就好了。
如果不带e,就变成吞异常了。
最后,为什么500不能随便抛呢?
正常来说,很多大公司都会监控http返回码,如果是500是要告警的,发邮件发短信,半夜把程序员(你)叫起来去改问题的,有可能还会通报批评,很严重的!
好了,今天就先到这里,你们公司是怎么定义异常,怎么规范抛异常的呢?欢迎留言讨论。