Java中进行非空判断(自己的一点思考)

在开发中我们经常会碰到空指针问题,网上关于Java的空指针问题有很多解决方案,这里就不一一进行说明了。我参考了《阿里巴巴Java开发手册v1.4.0(详尽版)》中的几种场景

10. 【推荐】防止 NPE,是程序员的基本修养,注意 NPE 产生的场景:
1)返回类型为基本数据类型,return 包装数据类型的对象时,自动拆箱有可能产生 NPE。
 反例:public int f() { return Integer 对象}, 如果为 null,自动解箱抛 NPE。
2) 数据库的查询结果可能为 null。
3) 集合里的元素即使 isNotEmpty,取出的数据元素也可能为 null。
4) 远程调用返回对象时,一律要求进行空指针判断,防止 NPE。
5) 对于 Session 中获取的数据,建议 NPE 检查,避免空指针。
6) 级联调用 obj.getA().getB().getC();一连串调用,易产生 NPE。
正例:使用 JDK8 的 Optional 类来防止 NPE 问题。
复制代码

规范中针对集联调用提到了Optional,我也搜集了一下这个工具类的使用方法,Java 8新特性(三):Optional类,觉得这个工具类使用起来有一定的优势。但是有一定的局限性:

  1. 如果是一个链还好,如果是两个或者更多会不太方便。比如:
obj.getA().getB().getC();
obj.getAA().getBB().getCC();
obj.getAAA().getBBBB().getCCC()
复制代码

这样层级复杂的情况将会比较难处理,需要一个链一个链去判断处理。
我在的项目开发中也经常会遇到这样的问题,一层一层的判断让我要疯了。所以我一直在追寻一种方式可以免去这么多的判断。

探索之路
  1. obj.getA().getB().getC() 如果不加判断直接使用,可能会导致NPE,那么捕捉NPE不就行了。于是
try{
   obj.getA().getB().getC();
   //正常处理
}catch (NullPointerException e){
    //异常处理
}
复制代码

但是也不能到处写try catch,有点low,于是封装一下。
2. 封装过程比较曲折,考虑了各种情况,一遍一遍修改,最终的样子。

public class ObjectNullUtil {

    /**
     * 只要成功情况下的回调
     * @param callBack 成功的回调
     * @param <T> 返回值的类型
     * @return
     */
    public static <T> T fixNull(CallBack<T> callBack){
        return fixNull(callBack, null);
    }

    /**
     * 需要成功和发生空指针情况下的回调
     * @param callBack 成功的回调
     * @param exceptionCallBack 空指针情况下的回调
     * @param <T> 返回值的类型
     * @return
     */
    public static <T> T fixNull(CallBack<T> callBack, NullPointerExceptionCallBack<T> exceptionCallBack){
        try{
            if (callBack != null) {
                return callBack.call();
            }
        }catch (NullPointerException e){
            if (exceptionCallBack != null) {
                return exceptionCallBack.call(e);
            }
        }
        return null;
    }

}

public interface CallBack<T> {
    T call();
}

public interface NullPointerExceptionCallBack<T> {
    T call(NullPointerException e);
}
复制代码

使用上

  • 第一种 要一个参数的
public void f1(String string){
    if (string == null){
        return;
    }
    Toast.makeText(MainActivity.this, ""+string.length(), Toast.LENGTH_SHORT).show();
}

public String f2(){
    String s = ObjectNullUtil.fixNull(new CallBack<String>() {
        @Override
        public String call() {
            UserInfo userInfo = new UserInfo();
            //这块会导致空指针
            userInfo.student = null;
            return userInfo.student.stuName;
        }
    }, new NullPointerExceptionCallBack<String>() {
        @Override
        public String call(NullPointerException e) {
            e.printStackTrace();
            return "error";
        }
    });
    return s;
}

findViewById(R.id.tv3).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        f1(f2());
    }
});
复制代码
  • 第二种 需要多个参数的
public void f3(String s1, String s2){
    if (s1 == null || s2 == null){
        return;
    }
    Toast.makeText(MainActivity.this, "" + s1 + s2, Toast.LENGTH_SHORT).show();
}

public void f4(){
    ObjectNullUtil.fixNull(new CallBack() {
        @Override
        public Object call() {
            UserInfo userInfo = new UserInfo();
            //这块会导致空指针
            userInfo.student = null;
            userInfo.bank = null;
            f3(userInfo.student.stuName, userInfo.bank.bankCardNo);
            return null;
        }
    });
}

findViewById(R.id.tv3).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        f4();
    }
});
复制代码

我的这种方式不能从根本上杜绝NPE,也不能完全去掉对参数的非空判断,但是能在部分场景下减少if(o != null)的次数。有好的想法欢迎大家一起探讨。如果觉得我设计的不合理也欢迎指出,一起思考更好的方式。

转载于:https://juejin.im/post/5c5ff15f518825620a7f002e

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值