news 2026/6/10 10:58:05

UtilEmpty空值检查工具类

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
UtilEmpty空值检查工具类

* 提供高效、标准的空值检查功能。
* 支持 POJO 对象的递归字段检查(作为最后优先级。

import java.lang.reflect.Array; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; /** * 空值检查工具类 * <p> * 提供高效、标准的空值检查功能。 * 支持 POJO 对象的递归字段检查(作为最后优先级),并针对 JDK 内置对象进行优化。 * </p> * * @author LXD * @version 1.0.1 */ public final class UtilEmpty { /** * 缓存字段信息,避免重复反射调用 */ private static final ClassValue<Field[]> FIELD_CACHE = new ClassValue<Field[]>() { @Override protected Field[] computeValue(Class<?> type) { List<Field> fields = new ArrayList<>(); // 获取所有声明的字段,包括私有字段 for (Field field : type.getDeclaredFields()) { // 排除静态字段和 transient 字段 if (!Modifier.isStatic(field.getModifiers()) && !Modifier.isTransient(field.getModifiers())) { try { field.setAccessible(true); fields.add(field); } catch (Exception ignored) { // 忽略无法设置访问权限的字段(如模块系统限制) } } } return fields.toArray(new Field[0]); } }; /** * 私有构造函数,防止实例化 */ private UtilEmpty() { throw new UnsupportedOperationException("Utility class"); } // ================================================================================= // 核心判空方法 (Overloads for Performance) // ================================================================================= /** * 检查字符串是否为空 * * @param str 字符串 * @return 如果字符串为 null 或仅包含空白字符,则返回 true */ public static boolean isNull(String str) { return isBlank(str); } /** * 检查集合是否为空 * * @param collection 集合 * @return 如果集合为 null 或不包含元素,则返回 true */ public static boolean isNull(Collection<?> collection) { return collection == null || collection.isEmpty(); } /** * 检查 Map 是否为空 * * @param map Map * @return 如果 Map 为 null 或不包含映射,则返回 true */ public static boolean isNull(Map<?, ?> map) { return map == null || map.isEmpty(); } /** * 检查对象数组是否为空 * * @param array 数组 * @return 如果数组为 null 或长度为 0,则返回 true */ public static boolean isNull(Object[] array) { return array == null || array.length == 0; } /** * 检查数值是否为 null (注意:0 不会被视为 null) * * @param number 数值 * @return 如果数值为 null,则返回 true */ public static boolean isNull(Number number) { return number == null; } /** * 检查布尔值是否为 null (注意:false 不会被视为 null) * * @param bool 布尔值 * @return 如果布尔值为 null,则返回 true */ public static boolean isNull(Boolean bool) { return bool == null; } // ================================================================================= // 通用判空方法 // ================================================================================= /** * 检查对象是否为空 * <p> * 规则:<br> * 1. null -> true <br> * 2. CharSequence -> 仅包含空白字符时为 true<br> * 3. Collection/Map -> isEmpty() 为 true<br> * 4. Array -> length == 0 为 true<br> * 5. Optional -> !isPresent() 为 true<br> * 6. Iterator/Iterable -> !hasNext() 为 true<br> * 7. 其他对象 (POJO) -> 递归检查所有字段,若所有字段均为空则返回 true<br> * 注意:java.* 和 javax.* 开头的类被视为值对象,只要不为 null 即视为不为空<br> * </p> * * @param object 要检查的对象 * @return 如果对象符合上述空值规则,则返回 true */ public static boolean isNull(Object object) { if (object == null) { return true; } // 优先检查最常见的类型 if (object instanceof String) { return isBlank((String) object); } if (object instanceof Collection) { return ((Collection<?>) object).isEmpty(); } if (object instanceof Map) { return ((Map<?, ?>) object).isEmpty(); } if (object instanceof Object[]) { return ((Object[]) object).length == 0; } // 处理其他特定类型 if (object instanceof CharSequence) { return isBlank((CharSequence) object); } // 原始类型数组处理 (int[], byte[] 等) Class<?> clazz = object.getClass(); if (clazz.isArray()) { return Array.getLength(object) == 0; } if (object instanceof Optional) { return !((Optional<?>) object).isPresent(); } if (object instanceof Iterable) { return !((Iterable<?>) object).iterator().hasNext(); } if (object instanceof Iterator) { return !((Iterator<?>) object).hasNext(); } // 基本类型包装类、Number、Boolean、Date 等通常被视为值对象,不应被递归检查 // 为了安全和性能,跳过 JDK 内部类的反射检查 String className = clazz.getName(); if (className.startsWith("java.") || className.startsWith("javax.")) { return false; } // POJO 反射检查 (作为最后手段) return isPojoEmpty(object, clazz); } // ================================================================================= // 扩展辅助方法 // ================================================================================= /** * 检查对象是否不为空 * * @param object 对象 * @return 如果对象不为空,则返回 true */ public static boolean isNotNull(Object object) { return !isNull(object); } /** * 检查数值是否为 null 或 0 * <p> * 适用于需要将 0 视为"空"的特定业务场景 * </p> * * @param number 数值 * @return 如果数值为 null 或 0,则返回 true */ public static boolean isNullOrZero(Number number) { if (number == null) { return true; } if (number instanceof BigDecimal) { return BigDecimal.ZERO.compareTo((BigDecimal) number) == 0; } if (number instanceof BigInteger) { return BigInteger.ZERO.compareTo((BigInteger) number) == 0; } if (number instanceof Double || number instanceof Float) { return number.doubleValue() == 0.0; } return number.longValue() == 0L; } // ================================================================================= // 私有实现细节 // ================================================================================= /** * 检查 POJO 对象是否所有字段都为空 * * @param object 对象实例 * @param clazz 对象类 * @return 如果所有字段都为空,则返回 true */ private static boolean isPojoEmpty(Object object, Class<?> clazz) { Field[] fields = FIELD_CACHE.get(clazz); if (fields.length == 0) { // 如果对象没有字段(且不是上述已知集合类型),则视为不为空(即它本身就是一个非空对象实例) return false; } for (Field field : fields) { try { Object value = field.get(object); // 只要有一个字段不为空,整个对象就不为空 if (!isNull(value)) { return false; } } catch (IllegalAccessException e) { // 理论上不会发生,因为在 cache 中已经 setAccessible(true) // 如果发生,为了安全起见,认为该字段不为空(保守策略)或忽略该字段 // 这里选择忽略该字段继续检查其他字段 } } // 所有字段都为空 return true; } /** * 检查 CharSequence 是否为空或空白 */ private static boolean isBlank(CharSequence cs) { int length; if (cs == null || (length = cs.length()) == 0) { return true; } for (int i = 0; i < length; i++) { if (!Character.isWhitespace(cs.charAt(i))) { return false; } } return true; } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 11:35:28

解放双手的5大技术突破:MAA如何让明日方舟玩家效率提升3倍

解放双手的5大技术突破&#xff1a;MAA如何让明日方舟玩家效率提升3倍 【免费下载链接】MaaAssistantArknights 一款明日方舟游戏小助手 项目地址: https://gitcode.com/GitHub_Trending/ma/MaaAssistantArknights 你是否曾经计算过&#xff0c;每周在《明日方舟》中花费…

作者头像 李华
网站建设 2026/6/10 11:44:25

GEO优化投资深度解析:从成本模型看布谷如何重塑AI营销

摘要在AI搜索浪潮席卷的当下&#xff0c;生成式引擎优化&#xff08;GEO&#xff09;正成为品牌获取下一代流量的关键战略。然而&#xff0c;其投资回报率&#xff08;ROI&#xff09;究竟如何衡量&#xff0c;与传统搜索引擎优化&#xff08;SEO&#xff09;相比有何根本性优势…

作者头像 李华
网站建设 2026/6/10 11:35:58

Java 开发内卷到 “无业可卷”?为什么说不如直接学网络安全?

一、先看一组扎心对比&#xff1a;市场真的不一样 程序员 &#xff1a;2024 智联招聘数据显示&#xff0c;Java 开发岗平均 1 岗 38 人竞争&#xff0c;应届生起薪中位数仅 7800 元&#xff1b;某大厂 2024 校招开发岗简历通过率不足 5%&#xff0c;且明确要求 “211/985 或顶…

作者头像 李华
网站建设 2026/6/10 1:26:10

Vue 组件解耦实践:用回调函数模式替代枚举类型传递

Vue 组件解耦实践&#xff1a;用回调函数模式替代枚举类型传递 前言 在 Vue 组件开发中&#xff0c;父子组件通信是一个常见场景。当子组件需要触发父组件的某个操作&#xff0c;而父组件又需要根据触发来源执行不同逻辑时&#xff0c;很容易写出耦合度较高的代码。本文通过一个…

作者头像 李华
网站建设 2026/6/10 11:23:56

52、Linux系统性能监测、故障排查与网络配置全解析

Linux系统性能监测、故障排查与网络配置全解析 1. 系统性能监测与故障排查基础 在Linux系统中,我们常常需要对系统性能进行监测,以便及时发现并解决潜在的问题。以下是一些常见的性能监测命令及相关问题分析。 1.1 性能监测命令选择题分析 sar命令中%idle指标分析 :当执…

作者头像 李华