【Java】Objects 工具类全解|告别空指针,开发必备工具类

大家好,我是云扬。日常 Java 开发里,空指针异常(NullPointerException) 绝对是高频踩坑点,频繁手写if(obj == null)不仅代码啰嗦,还容易遗漏判断。JDK1.8 新增的java.util.Objects工具类封装了各类对象安全操作方法,专门用来优雅处理空值校验、对象比对、哈希取值等场景,今天结合实战代码,一次性梳理 Objects 全部常用 API。

一、前置导入

Objects 位于java.util包下,使用前必须先导包:

import java.util.Objects;
import java.util.Comparator;

二、基础判空:isNull () & nonNull ()

替代原生==null / !=null做对象空判断,代码语义更直观,推荐项目中统一规范使用。

  • isNull(Object obj):对象为 null 返回 true,反之 false
  • nonNull(Object obj):对象非 null 返回 true,反之 false

代码示例

public class ObjectsTest {
    public static void main(String[] args) {
        String str1 = null;
        String str2 = "云扬のBlog";

        // isNull 判断是否为空
        System.out.println(Objects.isNull(str1));  // true
        System.out.println(Objects.isNull(str2));  // false

        // nonNull 判断是否非空
        System.out.println(Objects.nonNull(str1)); // false
        System.out.println(Objects.nonNull(str2)); // true

        // 业务场景:集合过滤非空元素
        // list.stream().filter(Objects::nonNull).forEach(System.out::println);
    }
}

开发小技巧:Stream 流过滤空元素时,Objects::nonNull是最优写法,可读性远优于自定义判空逻辑。

三、非空校验:requireNonNull () 参数校验神器

方法入参校验首选,对象为 null 直接抛出 NPE,支持三种重载,可自定义异常提示信息,多用于接口、工具类入参防御校验。

  1. requireNonNull(T obj):空则抛默认 NPE
  2. requireNonNull(T obj, String msg):空则抛携带自定义文案的 NPE
  3. requireNonNull(T obj, Supplier<String> msgSupplier):lambda 懒加载异常文案,空时才生成提示,性能更优

代码示例

// 模拟接口入参校验
public static void checkParam(Integer userId){
    // 1.默认异常信息
    Integer id1 = Objects.requireNonNull(userId);

    // 2.自定义异常提示字符串
    Integer id2 = Objects.requireNonNull(userId, "用户ID不能为空");

    // 3.lambda动态生成异常信息(懒加载,只有null才执行lambda)
    Integer id3 = Objects.requireNonNull(userId, () -> "参数异常:用户ID【"+userId+"】不能为空");
}

// 测试调用
public static void main(String[] args) {
    Integer num = null;
    checkParam(num); // 触发空指针异常,打印自定义提示
}

实际项目:Controller、Service 层入参校验,用这个方法替代一堆 if 判空,代码瞬间精简。

四、安全相等判断:Objects.equals ()

原生a.equals(b)如果 a 为 null,会直接空指针报错;Objects.equals(a,b)做了空值兼容,两边任意一方为 null 都不会抛异常,底层先做引用地址判断再调用对象自身 equals 方法。

代码示例

public static void main(String[] args) {
    String s1 = null;
    String s2 = "Java";
    String s3 = "Java";

    // 原生写法报错:s1.equals(s2) 空指针
    // Objects安全比对
    System.out.println(Objects.equals(s1,s2)); // false
    System.out.println(Objects.equals(s2,s3)); // true
    System.out.println(Objects.equals(null,null)); // true
}

注意:最终相等逻辑依赖实体类重写的equals(),如果实体没有重写 equals,依然走 Object 原生地址比对逻辑。

五、获取哈希值:Objects.hashCode ()

安全获取对象 hashCode,对象为 null 时直接返回 0,不会触发空指针。

public static void main(String[] args) {
    String str = null;
    String blog = "云扬のBlog";
    System.out.println(Objects.hashCode(str));    // 0
    System.out.println(Objects.hashCode(blog));    // 对应字符串哈希值
}

拓展:Objects.hash(字段1,字段2...)可快速生成多字段组合哈希,重写实体 hashCode 很方便。

六、对象排序比较:compare ()

配合Comparator比较两个对象,多用于自定义排序场景,入参比较器为 null 时使用对象自然排序。

class User{
    Integer age;
    User(Integer age){ this.age = age; }
}

public static void main(String[] args) {
    User u1 = new User(18);
    User u2 = new User(22);
    // 根据年龄升序比较
    int res = Objects.compare(u1, u2, Comparator.comparingInt(user -> user.age));
    System.out.println(res); // -1(u1小于u2)
}

七、数组深度比对:deepEquals ()

普通equals()只能比对数组地址,deepEquals()支持多维数组、元素递归深度比对,非数组对象用法和Objects.equals()一致。

public static void main(String[] args) {
    String[] arr1 = {"Java","MySQL"};
    String[] arr2 = {"Java","MySQL"};
    String[][] arr3 = {{"A"},{"B"}};
    String[][] arr4 = {{"A"},{"B"}};

    System.out.println(Objects.deepEquals(arr1,arr2));  // true
    System.out.println(Objects.deepEquals(arr3,arr4));  // true
}

文末小结

  1. isNull/nonNull:日常空值判断,规范代码;
  2. requireNonNull:参数校验标配,快速抛出非法入参异常;
  3. equals/deepEquals:规避空指针的安全比对,普通对象 / 数组分开选用;
  4. hashCode/compare:简化哈希生成与自定义排序。
Tags:

发表回复

Your email address will not be published. Required fields are marked *.

*
*