方式 1 和方式 2 的却别到底在哪里?

2019-11-16 11:13:45 +08:00
 Simle100

在开发中对于 a/b,这样的表达式,我们要做 b 的校验。但有两种方式: 方式 1: if ( b == 0 ) { // 提示除数不能为 0 } 方式 2: try{ a / b; } catch (ArithmeticException e){ // 提示除数不能为 0 } 这两种方式的差别是什么?是不是所有的处理异常的代码都被方式 1 取代?如果是这样,那么异常机制存在的理由是什么? 请大佬赐教。

6460 次点击
所在节点    Java
47 条回复
crclz
2019-11-16 23:54:15 +08:00
关于业务代码的错误处理,我的理解:
封装好的业务逻辑方法( HelperClass, Utils ),应当返回一个 Result。这个 Result 可以组织成这个结构:
{
ErrorCode String
Data Dictionary<string, string>
}
ErrorCode:用于给前端传递约定好的错误代码,例如'NicknameAlreadyExist'。
Data:用于给前端传递进一步细化错误的数据。例如前端传过来一个请求,要转账 400 元。你和前端约定,如果不足 400 元,为了告诉用户更多信息,就将它的余额{money: 300}加在 data 里面。
还可以设置一些字段支持多个错误代码,但我觉得大部分时间没必要。
还可以设置一些字段来告诉 http 请求发起者更多信息,详见各大 api 规范,例如 https://github.com/Microsoft/api-guidelines/blob/master/Guidelines.md
还可以设置一些字段来储存调试信息,这些信息可能会帮助到你再看错误日志的时候快速 debug。

但是,这样做有几个需要注意到的要点。

这样设计 HelperMethod 实际上是 Try-Parse Pattern。

HelperMethod 可能会被直接拿去用,也可能会被 HelperMethod 嵌套使用。当直接用的时候,调用者相当于客户端。当被其他 HelperMethod 嵌套调用的时候,大部分情况是像 GoLang 一样返回。也还有其他情况,例如:在方法 A 中,我调用方法 B。方法 A 的代码已经对一些条件进行了数据库的查询、检查。这些检查,可能碰巧的涵盖了方法 B 的检查。所以,方法 A 此时认为,对 B 的调用是一定会返回 success 的。所以如果返回了一个 error,那么就应当直接抛出异常(或者在 error 里附带这一层的某些有助于调试的信息),Exception.Data 里面附带这个 error。这很自然,因为这个内层的 error 不该返回给前端,因为用户会对这个 error 里面的内容可能会不知所云。
异常抛出了,然后被你的 http 框架( spring/WebApi )捕获,然后被你的 logger 记录。你去看 log,里面你记录的调试信息就可能会帮助你还原问题,尽快 debug.

---

跳出异常的话题。HelperClass 虽然被广泛使用,但有很多弊端。
在性能上,可能重复查数据库很多遍,检查某个条件。
在开发效率上,会出现领域知识的割裂、分散;持久层逻辑的污染;健忘。DDD 是解决方案。
MorningBOBO
2019-11-17 14:46:55 +08:00
方式 2,耗损一些性能,换取可读性.
cyspy
2019-11-17 20:46:34 +08:00
除 0 是可以被防御的,而大部分 IOException 是无法防御的
vjnjc
2019-11-17 21:56:57 +08:00
强烈赞同#8 的看法。
使用 Java 就是要用 Java 的方式。理论上别人声明一个方法可能跑出 A 异常,那你就不该去 if 判断做冗余的事情。因为有些 runtime 的问题很复杂,你检查过了不代表 if 后面的情况还适用
Simle100
2019-11-18 14:23:01 +08:00
@crclz @wysnylc @guyeu 等给位大佬的精彩辩论。
Simle100
2019-11-18 14:24:07 +08:00
@crclz @wysnylc @guyeu 等各位大佬的精彩辩论。
guyeu
2019-11-18 14:54:30 +08:00
@wysnylc #33 同意你的大部分内容,但是绝对不同意应该用异常来实现逻辑。
比如 b/a 这个场景,不要傻乎乎得直接除+捕捉除 0 异常,应该检查传入参数,
if (a == 0) throw new IllegalArguementsException("a cannot be zero.");

滥用异常来实现逻辑一方面大量的异常会造成效率损失,另一方面 try catch 块的确会侵入正常逻辑造成可读性变差。
另外,大多数开发者的能力并不足以驾驭实现这样的异常处理逻辑,所以,防御式编程,在发现问题之后抛出异常,但是不要制造问题。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/620135

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX