最近看到自己以前写的代码,许多的if表达式用作防御,没有写else,看的时分发生一些疑问,还有一些主意,由本文记载这些主意。

问题场景剖析

我想大部分开发者应该都写过相似下面的代码:

void fun1(Object obj){
    if(obj != null){
        handleObj(obj);
        //...
    }
}

这里对参数进行检查,只要在参数合法的时分才履行对应操作。而参数不合法的时分则疏忽,在代码中的体现为省掉的else。这个代码在大多数状况是没有问题的,但当我一段时间后再去看这段代码的时分,发生了一些疑问:这个else的状况是不需要处理的、能够疏忽的状况?还是忘掉写、疏忽了的状况?其实我不知道。乃至还有可能是写这段代码的时分,是能够疏忽的状况,但随着功用演化,变成了必需要处理的状况,但是却没有处理,这便是一种比较糟糕的状况了,但这也是项目中很容易呈现的状况。

优化和解决计划

下面共享几种优化和解决计划。

计划一、使用注释将else显式化

这种办法是不管什么状况都写else,但是在else的主体内,用注释阐明状况,例如:

void fun1(Object obj) {
    if (obj != null) {
        handleObj(obj);
    } else {
        // obj为null的状况可疏忽
    }
}

void fun1(Object obj) {
    if (obj != null) {
        handleObj(obj);
    } else {
        // 当时v1.0.0版别,不需要处理obj为null的状况
    }
}

这种办法就能够排除当初是忘掉写else的状况,也对else的状况做了具体阐明。

计划二、打印日志

注释能够避免省掉else而导致的解读代码时疑问,但在后面那种“可省掉变成不可省掉的状况”没有什么帮助,因为假如这个省掉导致反常状况,那么直接原因可能在非常遥远的另一段代码中,而难以追寻到这里的根本原因,所以实践项目中,咱们能够在else主体中打印日志,便利以后追寻问题:

void fun1(Object obj) {
    if (obj != null) {
        handleObj(obj);
    } else {
        Log.warn("预料之外的状况,请排查fun1中obj为null的状况");
    }
}

这样在项目更新迭代中,及时关注日志中的警告,能够提早发现一些隐患。

计划三、抛出反常

实践开发中,有时会比较仓促,就会疏忽日志,这种状况就该考虑用更激进、严格的方法,也便是抛出反常:

void fun1(Object obj) {
    if (obj != null) {
        handleObj(obj);
    } else {
        throw new RuntimeException("不期望的状况,请排查fun1中obj为null的状况");
    }
}

这样就能够在测试阶段及早发现问题,并快速定位本源。

写在最终

  1. switch以及模式匹配的default行为相似。
  2. 关于防御性代码有更好的解决计划,待后期独自写文章来总结。