⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 网络 「网络」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

空指针异常是出现频率比较高的bug,在出现空指针时,很多小伙伴都是习惯性地加一个 !=null 的判断,这个bug就解决了。

当代码中频繁出现 !=null 的判断时,我们就会很头疼,能不能高效、优雅地做这个判断?

答案当然是可以的。

第一步,当我们要做 !=null 的判断时,请停顿一下,看一下我们要做判断的这个数据是什么类型?

数据类型无非就是String字符串、Object/自定义对象、List集合、Array数组、Map集合等类型。

第二步,思考这个数据类型对应的工具类有哪些?

String类型,对应的工具类有StringUtils。

Object对象,对应的工具类有ObjectUtils。

Array数组,对应的工具类有Arrays。

List集合、Map集合对应的工具类有Collections、CollectionUtils等。

这些工具类都是Java、Spring框架自带的工具类。

第三步,使用对应类型的工具类做判断。

1、如果这个数据是String类型时,请使用StringUtils工具类。

String str = "";
StringUtils.isEmpty(str); // true

StringUtils工具类比较有针对性,是针对String字符串的工具类。

public static boolean isEmpty(@Nullable Object str) {
return str == null || "".equals(str);
}

在isEmpty方法中,既有为null的判断,也有是否等于空字符串的判断。

2、如果这个数据是Object类型,请使用ObjectUtils工具类。

Object obj = null;
ObjectUtils.isEmpty(obj); // true

3、如果这个数据是Map类型,也可以使用ObjectUtils工具类。

Map<String,Object> map = Collections.emptyMap();
ObjectUtils.isEmpty(map);// true

4、如果这个数据是List类型,还可以使用ObjectUtils工具类。

List<Integer> list =Collections.EMPTY_LIST;
ObjectUtils.isEmpty(list); // true

5、如果这个数据是数组类型,依旧可以使用ObjectUtils工具类。

// 数组
Object[] objArr = null;
ObjectUtils.isEmpty(objArr); // true

ObjectUtils 中的isEmpty()这一个方法,分别可以对字符串、数组、Map集合、List集合进行是否等于null的判断。

这个isEmpty方法为什么能判断这么多种数据类型呢?一起看下它的源码。

public static boolean isEmpty(@Nullable Object obj) {
// 判断obj是否为null,如果是直接f
if (obj == null) {
return true;
}
// 判断obj是否是Optional的子类
if (obj instanceof Optional) {
// 如果是,则调用isPresent方法判断是否为null
return !((Optional) obj).isPresent();
}
// 判断obj是否是CharSequence的子类
if (obj instanceof CharSequence) {
// 如果是,则获取长度,长度等于0时,就认为这个obj是空字符串
return ((CharSequence) obj).length() == 0;
}
// 判断obj是否为数组
if (obj.getClass().isArray()) {
// 数组的长度等于0就认为这个数组是空数组
return Array.getLength(obj) == 0;
}
// 判断obj是否为Collection集合的子类
if (obj instanceof Collection) {
// 用Collection子类的isEmpty方法判断集合是否为空
return ((Collection) obj).isEmpty();
}
// 判断obj是否为Map接口的子类
if (obj instanceof Map) {
// 如果是,则进行强转,并用子类的isEmpty方法判断集合是否为空
return ((Map) obj).isEmpty();
}

// else
return false;
}

在这个静态方法中,首先对传入的obj对象进行是否等于null的判断,如果是则返回。如果不是null,对obj进行数据类型进行定位,然后根据数据类型进行判断。

在这个方法中,封装了Optional、CharSequence、Array、Collection、Map数据类型,几乎涵盖所有的数据类型。

通过这段源码,我们也可以看出,它对复杂类型的集合的判断存在一些缺陷。也就是说它只判断了集合的长度,集合的长度为0,就认为集合是空的。

// 创建一个只有一个元素的List集合
List<Integer> list = Collections.singletonList(null);
ObjectUtils.isEmpty(list); // false

上面的这段代码,我们创建了一个只有一个元素、且这个元素为null的List集合。

如果是对象数组,数组里有一个对象,但这一个对象为null,这个判断就失灵了。

ObjectUtils 类中对对象数组的判断是另外一个isEmpty方法。

public static boolean isEmpty(@Nullable Object[] array) {
return array == null || array.length == 0;
}

因此在这2种情况下,我们再使用ObjectUtils的isEmpty方法就不合适了,我们需要对集合或数组里的每一个元素进行判断是否为null。

6、针对List集合中元素是否为空的正确判断

Arrays.stream(list.toArray()).allMatch(ObjectUtils::isEmptyisNull);

这里用到了Arrays工具类。需要先把List集合转换成数组,然后再使用Arrays工具类对数组里的元素逐一判断是否为null。

7、针对Map集合是否为空为null的判断

Map<String,Object> map = Collections.emptyMap();
CollectionUtils.isEmpty(map);

CollectionUtils工具类中isEmpty判断方法源码:

public static boolean isEmpty(@Nullable Map<?, ?> map) {
return map == null || map.isEmpty();
}

map是否等于null,map集合是否为空,这一个方法中聚合了两个判断。我们直接调用它就可以减少我们的工作量。

除此之外,CollectionUtils工具类中还有针对List集合的isEmpty方法:

List<Integer> list = null;
// 使用CollectionUtils工具类判断list集合是否为空
CollectionUtils.isEmpty(list); // true

针对List集合的isEmpty源码:

public static boolean isEmpty(@Nullable Collection<?> collection) {
return collection == null || collection.isEmpty();
}

在这个方法中,既有为null的判断,也有isEmpty的判断,聚合了两个判断,我们直接调用它也可以减少我们的工作量。

最后总结一下

判断一个数据是否为null,可以经过三步,第一步思考属于什么数据类型,第二步根据数据类型选择正确的工具类,第三步,使用正确的工具类进行判断。

针对String字符串类型的数据,直接使用StringUtils工具类。

针对除了String之外的数据类型都可以使用ObjectUtils工具类。

针对List集合、Map集合,除了ObjectUtils还可以使用CollectionUtils工具类进行判断。

针对数组和List集合中的子元素是否都为null的判断,则需要遍历判断。

以上便是本次的总结,希望对你有帮助。

文章目录