【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,反之 falsenonNull(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,支持三种重载,可自定义异常提示信息,多用于接口、工具类入参防御校验。
requireNonNull(T obj):空则抛默认 NPErequireNonNull(T obj, String msg):空则抛携带自定义文案的 NPErequireNonNull(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
}
文末小结
isNull/nonNull:日常空值判断,规范代码;requireNonNull:参数校验标配,快速抛出非法入参异常;equals/deepEquals:规避空指针的安全比对,普通对象 / 数组分开选用;hashCode/compare:简化哈希生成与自定义排序。



