检验入参合法性有哪些_在函数的入口处对参数的合法性进行检查是一个值得提倡的好习惯吗?...

无邀强答。以非性能敏感的JAVA业务系统为背景谈谈我的看法吧。“非性能敏感”这个前提好像很取巧,但毕竟当今高性能敏感的系统在整个软件行业占得不多了。如果你能用profiling证明软件中的校验真的造成了不容忽视的性能问题,那么在你的场景中就不存在取舍的考虑,肯定是以满足基本的性能需要为优先。

简单版答案:任何有可能被另一个不了解详细实现细节的程序员调用的函数,都应该在函数入口处尽快对参数进行校验。对应到java的具体操作就是:非私有方法,一律在入口处进行参数校验;私有方法根据类的规模和方法性质来定。(未重构拆分,其他程序员有可能在不了解整个类的全貌的情况下进行局部维护的大类,一些提供公用逻辑的私有方法也应该进行参数校验)

详细版答案:

首先口头反对一下那些认为这是防御式与契约式编程之争的答案。契约式编程的意思不是指通过文档把契约告诉调用者然后假设对方总是遵守契约,而是指在程序中仅仅对契约进行约束。题目中的“在函数入口校验”恰恰就是契约式编程。当然在Java里契约式编程也包括了利用静态语言的类型系统了维护接口契约,但类型系统无法顾及的业务约束,那就用代码在入口处进行约束。至于防御式编程那是比契约式更保守的做法,在内部实现细节中每一个可能出错的点上都进行判断,目标是所有异常可能都由本段程序来掌控。而题目中所说的“出于性能考虑,连契约都不校验”那显然也不会处处防御(更耗性能)。既不是契约式也不是防御式,一定要命名的话我觉得应该叫校园作业式,特点就是只管实现主线功能其余啥都不管。

作为一个产品级的函数,即使编写者认为应该由调用者保证传入参数正确,但编写者还是需要保证在调用者出错的时候,你的函数能告诉调用者TA搞错了,最好是给出相对有意义的错误原因。总不能说因为我早就给你定了契约,作为对你不遵守契约的惩罚,我给你来个垃圾进垃圾出,抛个NullPointerException都算是给面子了,返回成功但事实上没写入数据也是有可能的喔。但谁能保证自己永不出错呢,我出点小错你给我把事情闹得震动党中央这算是谁的锅?

再细分一点说,你不在函数入口处检查契约,那么对于错误传入无非会有以下情况:

1. 在实际使用的位置校验。性能上和代码风格上比起在入口处检查都没有任何进步(完全不校验在代码风格上至少减少了一点噪音)。但在入口处校验有一个显著好处是这些校验代码本身可以充当文档(也就是所谓的契约)。而且维护时我可以轻易看出有哪些参数校验过,哪些没有(忘了校验)。而把它们分散在实现细节中则浪费了这个机会。

2. 垃圾进垃圾出。返回一个无意义甚至误导的结果。这是最坏的情况,老实说这算是调用者的问题还是函数编写者的问题绝对会扯皮,而且多数人会倾向后者。

3. 抛NullPointerExceptiin。其他语言我不评价,但在JVM语言中,抛NullPointerException这种事最好尽量避免。也就是说所有理论上可控的情况,都不应该任由系统抛出NPE或程序主动抛出NPE。连自己抛出了NPE又立马catch的做法都应该避免。因为JVM上有个调试神器叫Exception Breakpoint (异常断点)。任何本来可控但你没有去控而被抛出来的NPE,都有可能在将来干扰你对真正不可控的NPE(比如说在第三方包中抛出来的)使用异常断点。原则上,所有可控的NPE都应该至少改为抛出IllegalAgumentException或IllegalStateException。当然,这离不开参数校验。

4. 如果某个参数在本函数中完全没有直接使用,仅仅是传递给另一个第三方函数处理。那么本函数不做任何额外校验,任由第三方函数处理。如果这个第三方函数所依赖的概念模型跟本函数一致而且不会跟本函数冲突,或者你确认调用者一定能理解这个第三方函数的所使用的概念,这倒也没有大碍。这里说说概念冲突,比如说你的函数契约是找不到记录就抛NPE(早期的hibernate就干过这事),而其中依赖了另一个函数,如果你传入了某个非法参数它就会抛NPE。你不做校验的话,调用者就会根据本函数的契约认为没有该记录(即使该记录存在)。那么可能导致在后面十万八千里的地方抛出主键冲突异常,甚至干脆不抛异常将错误的数据成功写入数据库。至于如何确定是否存在概念冲突,得看具体情况,不过大部分情况我觉得还是不管三七二十一都对参数在本函数的业务概念下进行校验反而更方便,至少可以减少此类情况发生而不用依赖于一个我不可控的函数。而且如前所述入口处的校验兼具文档功能。何乐而不为。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值