最近看到自己以前写的代码,很多的if表达式用作防御,没有写else,看的时候产生一些疑惑,还有一些想法,由本文记录这些想法。
问题场景分析
我想大部分开发者应该都写过类似下面的代码:
java
复制代码
void fun1(Object obj){ if(obj != null){ handleObj(obj); //... } }
这里对参数进行检查,只有在参数合法的时候才执行对应操作。而参数不合法的时候则忽略,在代码中的体现为省略的else。这个代码在大多数情况是没有问题的,但当我一段时间后再去看这段代码的时候,产生了一些疑惑:这个else的情况是不需要处理的、可以忽略的情况?还是忘记写、疏忽了的情况?其实我不知道。甚至还有可能是写这段代码的时候,是可以忽略的情况,但随着功能演变,变成了必须要处理的情况,但是却没有处理,这就是一种比较糟糕的情况了,但这也是项目中很容易出现的情况。
优化和解决方案
下面分享几种优化和解决方案。
方案一、利用注释将else显式化
这种方法是不管什么情况都写else,但是在else的主体内,用注释说明情况,例如:
java
复制代码
void fun1(Object obj) { if (obj != null) { handleObj(obj); } else { // obj为null的情况可忽略 } }
或
java
复制代码
void fun1(Object obj) { if (obj != null) { handleObj(obj); } else { // 当前v1.0.0版本,不需要处理obj为null的情况 } }
这种方法就可以排除当初是忘记写else的情况,也对else的情况做了详细说明。
方案二、打印日志
注释可以避免省略else而导致的解读代码时疑惑,但在后面那种“可省略变成不可省略的情况”没有什么帮助,因为如果这个省略导致异常情况,那么直接原因可能在非常遥远的另一段代码中,而难以追踪到这里的根本原因,所以实际项目中,我们可以在else主体中打印日志,方便以后追踪问题:
java
复制代码
void fun1(Object obj) { if (obj != null) { handleObj(obj); } else { Log.warn("预料之外的状况,请排查fun1中obj为null的情况"); } }
这样在项目更新迭代中,及时关注日志中的警告,可以提前发现一些隐患。
方案三、抛出异常
实际开发中,有时会比较仓促,就会忽略日志,这种情况就该考虑用更激进、严格的方式,也就是抛出异常:
java
复制代码
void fun1(Object obj) { if (obj != null) { handleObj(obj); } else { throw new RuntimeException("不期望的状况,请排查fun1中obj为null的情况"); } }
这样就可以在测试阶段及早发现问题,并快速定位根源。
写在最后
- switch以及模式匹配的default行为类似。
- 关于防御性代码有更好的解决方案,待后期单独写文章来总结。
作者:乐征skyline
链接:https://juejin.cn/post/7236383034558513209