2021-11-26 判空

2021.11.26

NullPointerException 是 Java 代码中最常见的异常,我将其最可能出现的场景归为以下 5 种:

参数值是 Integer 等包装类型,使用时因为自动拆箱出现了空指针异常;

字符串比较出现空指针异常;

诸如 ConcurrentHashMap 这样的容器不支持 Key 和 Value 为 null,强行 put null 的 Key 或 Value 会出现空指针异常;

级联调用,A 对象包含了 B,在通过 A 对象的字段获得 B 之后,没有对字段判空就级联调用 B 的方法出现空指针异常;

方法或远程服务返回的 List 不是空而是 null,没有进行判空就直接调用 List 的方法出现空指针异常。

  可以利用 Java 8 的 Optional 类来消除这样的 if-else 逻辑

  使用Optional.of(T value),如果value是null就会手动抛出NullPointerException(),所以,使用该方法格外注意,不能有null。

  Optional.ofNullable(T value) ,如果value为null,那么就会手动创建一个new Optional();但是this.value = null。所以这个时候就跳出了手动抛空指针那个代码块。这个时候,我们就可以使用orElse(T other)。看源码,如果value == null,那么将取other的值。

   

使用判空方式或 Optional 方式来避免出现空指针异常,不一定是解决问题的最好方式,空指针没出现可能隐藏了更深的 Bug。因此,解决空指针异常,还是要真正 case by case 地定位分析案例,然后再去做判空处理,而处理时也并不只是判断非空然后进行正常业务流程这么简单,同样需要考虑为空的时候是应该出异常、设默认值还是记录日志等。

POJO中的null代表了什么?

明确 DTO 中 null 的含义。对于 JSON 到 DTO 的反序列化过程,null 的表达是有歧义的,客户端不传某个属性,或者传 null,这个属性在 DTO 中都是 null。但,对于用户信息更新操作,不传意味着客户端不需要更新这个属性,维持数据库原先的值;传了 null,意味着客户端希望重置这个属性。因为 Java 中的 null 就是没有这个数据,无法区分这两种表达,所以本例中的 age 属性也被设置为了 null,或许我们可以借助 Optional 来解决这个问题。POJO 中的字段有默认值。如果客户端不传值,就会赋值为默认值,导致创建时间也被更新到了数据库中。注意字符串格式化时可能会把 null 值格式化为 null 字符串。比如昵称的设置,我们只是进行了简单的字符串格式化,存入数据库变为了 guestnull。显然,这是不合理的,也是开头我们说的笑话的来源,还需要进行判断。DTO 和 Entity 共用了一个 POJO。对于用户昵称的设置是程序控制的,我们不应该把它们暴露在 DTO 中,否则很容易把客户端随意设置的值更新到数据库中。此外,创建时间最好让数据库设置为当前时间,不用程序控制,可以通过在字段上设置 columnDefinition 来实现。数据库字段允许保存 null,会进一步增加出错的可能性和复杂度。因为如果数据真正落地的时候也支持 NULL 的话,可能就有 NULL、空字符串和字符串 null 三种状态。如果所有属性都有默认值,问题会简单一点。

MySQL 中 sum 函数没统计到任何记录时,会返回 null 而不是 0,可以使用 IFNULL 函数把 null 转换为 0;

MySQL 中 count 字段不统计 null 值,COUNT(*) 才是统计所有记录数量的正确方式。

MySQL 中使用诸如 =、<、> 这样的算数比较操作符比较 NULL 的结果总是 NULL,这种比较就显得没有任何意义,需要使用 IS NULL、IS NOT NULL 或 ISNULL() 函数来比较。

ConcurrentHashMap

ConcurrentHashMap 的 Key 和 Value 都不能为 null,而 HashMap 却可以,你知道这么设计的原因是什么吗?

HashMap源码:

612行:hash()方法计算了key的值

339行:当key为null时,计算出的hash值为0,value放置在第0个桶上

ConcurrentHashMap源码:

1006行:没有像HashMap一样先计算hash

1011行:先进行了判断key和value是否为null

为什么ConcurrentHashMap需要加空值校验呢?

因为存在二义性问题且ConcurrentHashMap没法解决

HashMap与ConcurrentHashMap的区别?

HashMap不支持并发操作,没有同步方法,ConcurrentHashMap支持并发操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值