曾经写了一段代码,在最逻辑外层捕获了空指针,因为内部逻辑出现空指针一定是数据查不到导致的异常,所以方便处理,我统一在最外层捕获空指针打印 xxx 数据查不到的日志。结果被项目总监拿出来吐槽了。说空指针为什么要去捕获他。让我调整这段代码。然后我就得在内部逻辑判断多个 if 语句去 isEmpty 判断是否为空。。
就是想了解下,我原先这种处理方式是不合适还是异常本身就不应该去捕获再做逻辑判断。
1
Renco OP 有时候我会用,异常捕获来做一些逻辑操作,虽然比较少,这种处理模式是比较非主流的么
|
2
abersheeran 2022-06-20 15:58:47 +08:00
不建议最外层捕捉这种通用异常。因为你没办法保证这个异常会不会出现在其他你没想到的地方。
最外层捕捉异常的逻辑一般都是捕捉自己定义的异常,因为能清楚知道它会在什么时候出现、以及该如何处理。 |
3
jjwjiang 2022-06-20 15:59:07 +08:00 3
在可能为空的地方处理空值是一个码农的基本素养之一
|
4
Renco OP @abersheeran 好吧 清楚了。
|
6
rekulas 2022-06-20 16:04:47 +08:00
我也支持你总监的做法,你在外部捕获虽然表面方便但有这样的问题:
1 你可能很难确定空指针具体是哪个逻辑导致的 2 正常逻辑执行时如果不及时处理空指针有可能出现数据错误-一些本不应该执行到的逻辑被处理了,从而引起 bug 可能还有其他问题... |
7
Renco OP @abersheeran 那如果我能保证我捕获的这段逻辑出现的空指针是我能确定的,可以这样处理么。
|
8
thinkershare 2022-06-20 16:06:18 +08:00
主要要看你处于什么层次, 你做的这个层的消费者是谁, 如果你作为一个底层库, 要看错误是谁导致的, 如果是用户入参有问题, 我们就是抛出异常, 如果是内部的不受控的上下文依赖导致的问题, 也是直接抛给调用者, 如果是内部业务逻辑错误, 也直接抛给调用者. 如果是外部调用者(普通用户或第三方 API 调用者),那么就需要在外层统一处理一下. 主要是大部分错误就没法处理. 直接返回给调用者. 主要是看是逻辑错误还是其它. 说白了, 异常是一种偷懒的流程控制手段, 看你怎么用.
|
10
hahaba 2022-06-20 16:06:53 +08:00
做法不对,你既然捕获到日志中了,就应该再写个脚本定时删除异常日志,这样就不会发现错误了
|
11
thinkershare 2022-06-20 16:11:47 +08:00
另外, 对外在能考虑到的情况是不会抛出系统级别的异常的. 如果事前没有考虑到, 那么就让他直接奔溃. 由宿主层去考虑要怎么执行下一步操作.
|
12
abersheeran 2022-06-20 16:11:52 +08:00 1
@Renco 你没法保证空指针异常一定出自你的这个逻辑。你不是神,你怎么预测未来的代码不会抛出其他情况的空指针异常?
如果你坚持在外层捕捉你这段逻辑的异常,我的建议是你在你的代码逻辑那儿捕捉空指针,重新抛出一个你自定义的异常。 |
13
Renco OP @abersheeran 可以,受教了
|
14
chaoschick 2022-06-20 16:18:27 +08:00 via Android
我也喜欢在 controller 层进行异常捕获,
|
15
chendy 2022-06-20 16:23:20 +08:00
空指针异常其实不方便统一处理,因为不知道什么东西是 null ,所以通常和其他异常一样,做为“系统异常”处理
一般做法是,业务逻辑里做 == null 判断然后抛自定义的异常 “未找到 xxx”,外加打日志 “id 是 xxx ,查询条件 xxx 的数据未找到” |
16
Saxton 2022-06-20 16:27:30 +08:00
难怪你被吐槽。。 我最近接手到一个项目全部用 try catch 来判空和判非法值,有几个参数是直接 get 的,但并非必填的, 无语死,整个方法拿个 try 套起来,省了几个 if ,你这确实爽了啊,后期维护的人怎么办,吐血给你看吗
|
17
Saxton 2022-06-20 16:28:41 +08:00 6
越想越气,楼主你在哪
|
18
AoEiuV020CN 2022-06-20 16:29:30 +08:00
不做空判断的话 idea 会有黄色警告,哪怕只是为了消除警告都可以加个空判断,
|
19
Saxton 2022-06-20 16:30:45 +08:00
代码一大堆全部是拿 try 来充当 if ,哪里出问题我必须开调试,不然我根本不知道到底是哪一个方法抛的异常,关键还是捕获的 exception ,我该他的代码还得开个 debug 一步一步走看看到底哪里蹦了
|
20
DonaldY 2022-06-20 16:32:21 +08:00
平时代码多考虑会儿,该 throw 的 throw ,该 try 的 try ,有异常的地方打好堆栈。
蔸底拦截是应该有的,提示需要给用户友好,而不是把错误显示在页面上。 |
22
Renco OP @Saxton 你这个确实恶心,大多数还是用 if 去判断的,也好定位问题。try catch 维护起来 定位错误会很痛苦
|
23
leafre 2022-06-20 17:13:14 +08:00
《 effective java 》:对于可恢复的条件使用被检查的异常( CheckedException ),对于程序错误使用运行时异常( RuntimeException )。
NPE 出现,就说明代码健壮性有问题,逻辑错误,快速定位修复,而不是捕获。 |
24
taest 2022-06-20 17:55:01 +08:00
如果出现未知的系统异常,那就让他抛出就完事了。
|
25
TWorldIsNButThis 2022-06-20 18:06:50 +08:00 via iPhone
我用 null safety 语言 没有这个烦恼
而且所有从 map 取值的操作(都是可为 null 的类型),如果业务上就是不会为 null 的都额外 checknotnull 并捕获上下文里的相关变量抛异常方便排查脏数据的问题 之前切回 java 写一个要处理 null 和 empty 的接口改了五次才改好 |
26
wonderblank 2022-06-20 18:10:38 +08:00
让它崩掉。
|
27
28Sv0ngQfIE7Yloe 2022-06-20 18:13:33 +08:00 3
@Saxton #17 乍一看我以为你要提刀砍楼主了
|
28
ekoaix 2022-06-20 18:44:38 +08:00
总的原则是:1 、在最贴近代码处、发生处进行处理。2 、你能处理就处理,处理不掉就抛出去处理,到能处理的地方去处理。:)有掉绕
|
29
kidlj 2022-06-20 18:54:00 +08:00
if err != nil {
// handle err } |
31
OutOfMemery 2022-06-20 19:58:51 +08:00
@Saxton #17 兄弟,刀放下,有话好好说🐶
|
32
dilu 2022-06-20 20:17:40 +08:00
goer:
if err != nil { log.Errorf(); } |
35
Red998 2022-06-20 20:36:04 +08:00
Optional 了解下
|
36
HackerJax 2022-06-20 21:06:57 +08:00 via iPhone
把你的 find 方法封一下叫 findOrThrowException ,在全局统一处理这里抛出的异常,顺便记上日志。这样在业务层就没必要 care 这种问题了
|
37
lmshl 2022-06-20 21:26:00 +08:00
我们用 Option / Either ,非必要不抛异常😏
|
38
dddd1919 2022-06-20 21:52:54 +08:00
很多场景的异常是可以预见到的,而且这种异常并称不上是异常,而是合理的逻辑分支,比如 lz 讲到的查不到数据,本来一个判断搞定的事非要抛异常,逻辑不但没有更清晰,还额外增加捕获异常的运行时开销。
如果想都用异常来处理的话,要把各处的异常做细分,保证哪些是可吞掉的哪些是需要抛出的。与其花精力管理异常,不如从源头处理好。当然从性能的角度讲,避免抛异常 |
39
ferock 2022-06-20 22:01:58 +08:00 via iPhone
有的时候问题需要暴露的,而不是兜底
|
40
Dogtler 2022-06-21 09:07:29 +08:00 via iPhone
Go 好像没有 try catch ,一般是判断 err panic 业务报错则 log 输出
|
41
pzs 2022-06-21 09:50:21 +08:00
一种处理方式:SpringBoot 项目进行全局异常的处理 https://www.cnblogs.com/xuwujing/p/10933082.html
|
42
thetbw 2022-06-21 13:37:50 +08:00
spring 或者 filter 统一处。然后除了业务的异常,比如用户经行了错误的操作。其他异常都应该后续解决,我是这么觉得
|