一、背景
在Java开发中,经常会遇到值为空(null
)时如何处理的场景。在这种情况下,我们需要提供默认值来避免空指针异常(NullPointerException
)或其他潜在的错误。在此背景下,DefaultUtil
工具类便提供了一个高效且易用的方式来处理不同类型的默认值。本文将详细解析该工具类的设计和实现。
二、介绍
2.1 工具类概述
DefaultUtil
是一个封装常用默认值处理方法的工具类,提供了以下几个主要功能:
- 为
null
值提供默认值:当传入的值为null
时,可以返回指定的默认值。 - 根据类型返回默认值:根据给定的类类型,返回其对应的默认值。
- 支持基本类型和引用类型:能够处理Java中的基本数据类型、包装类型、集合类型等常见对象类型。
2.2 代码结构与核心功能
2.2.1 类成员
private static final Map<Class<?>, Object> PRIMITIVE_DEFAULTS;
private static final Consumer<String> LOG_INFO = message -> log.info("[INFO] {}", message);
private static final BiConsumer<String, Throwable> LOG_ERROR = (message, throwable) -> log.error("[ERROR] {} ", message, throwable);
PRIMITIVE_DEFAULTS
:一个静态的Map
,用于存储Java中常见类型的默认值,如Integer
类型的默认值为0
,Boolean
的默认值为false
,等等。- 日志工具:使用
Slf4j
日志库,LOG_INFO
和LOG_ERROR
分别是用于记录信息日志和错误日志的Consumer
。
2.2.2 默认值初始化
在静态代码块中,PRIMITIVE_DEFAULTS
被初始化为一些基本数据类型的默认值映射,例如:
static {
PRIMITIVE_DEFAULTS = Stream.of(
new AbstractMap.SimpleEntry<>(int.class, 0),
new AbstractMap.SimpleEntry<>(Integer.class, 0),
new AbstractMap.SimpleEntry<>(long.class, 0L),
new AbstractMap.SimpleEntry<>(Long.class, 0L),
new AbstractMap.SimpleEntry<>(double.class, 0.0),
new AbstractMap.SimpleEntry<>(Double.class, 0.0),
new AbstractMap.SimpleEntry<>(boolean.class, false),
new AbstractMap.SimpleEntry<>(Boolean.class, false),
new AbstractMap.SimpleEntry<>(String.class, ""),
new AbstractMap.SimpleEntry<>(List.class, Collections.emptyList())
// 添加其他类型映射
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
这段代码通过 Stream
API 构造一个 Map
,将每个类型与其默认值相关联。通过这个 Map
,我们可以非常高效地为常见类型提供默认值。
2.3 defaultIfNull
方法
defaultIfNull
是该工具类的核心方法之一,具有两种重载形式:
- 当值为
null
时返回指定的默认值:
public static <T> T defaultIfNull(T value, T defaultValue) {
return Optional.ofNullable(value).orElse(defaultValue);
}
- 当值为
null
时,根据类型返回默认值:
public static <T> T defaultIfNull(T value, Class<T> clazz) {
return Optional.ofNullable(value).orElseGet(() -> getDefaultValue(clazz));
}
这两个方法都基于 Optional.ofNullable
,其优点是代码简洁,并且能够有效避免空指针异常。
2.4 getDefaultValue
方法
该方法根据给定的类型返回其默认值:
public static <T> T getDefaultValue(Class<T> clazz) {
if (clazz == null) {
return null;
}
// 如果是 Optional 类型,返回空 Optional
if (clazz.equals(Optional.class)) {
return (T) Optional.empty();
}
// 从映射中获取默认值
T defaultValue = (T) PRIMITIVE_DEFAULTS.get(clazz);
if (defaultValue != null) {
return defaultValue;
}
// 对于集合类型,返回空集合
if (Collection.class.isAssignableFrom(clazz)) {
return createEmptyCollection(clazz);
}
// 对于 Map 类型,返回空 Map
if (Map.class.isAssignableFrom(clazz)) {
return (T) Collections.emptyMap();
}
// 尝试通过反射创建对象
return createInstance(clazz);
}
此方法首先检查 clazz
是否为 Optional
类型,如果是,则返回 Optional.empty()
。接着,查询 PRIMITIVE_DEFAULTS
来获取预定义的默认值。如果映射中没有找到,则根据类型返回一个空集合、空 Map
,或者通过反射创建一个新的实例。
2.5 创建空集合或空对象
对于集合类型(如 List
, Set
),createEmptyCollection
方法返回空集合;对于非基本类型对象,createInstance
方法则通过反射来实例化对象。
2.3 示例与使用
2.3.1 基本类型的默认值
logInfo("defaultInt = " + defaultIfNull(null, Integer.class)); // 输出:0
logInfo("defaultBoolean = " + defaultIfNull(null, Boolean.class)); // 输出:false
2.3.2 集合类型的默认值
logInfo("defaultList = " + defaultIfNull(null, ArrayList.class)); // 输出:[]
logInfo("defaultSet = " + defaultIfNull(null, HashSet.class)); // 输出:[]
2.3.3 自定义类型的默认值
logInfo("defaultCustomType = " + defaultIfNull(null, CustomType.class)); // 输出:CustomType(name=null)
2.4 优缺点分析
2.4.1 优点:
- 代码简洁:通过
Optional
和默认值映射表,简化了对null
值的处理。 - 易于扩展:可以轻松扩展,支持新的类型或者复杂类型。
- 反射与类型安全:通过反射创建实例,能够处理未知类型,增强了工具类的通用性。
2.4.2 缺点:
- 性能开销:在处理大量
null
值时,使用反射可能会带来一定的性能损耗。 - 不支持复杂类型的深度初始化:例如,如果自定义类型的属性为
null
,该工具类并不会自动为其初始化。
三、总结
DefaultUtil
工具类是一个非常实用的工具,能够帮助开发人员在处理 null
值时,快速返回合适的默认值。通过预定义的类型映射和反射机制,它不仅支持Java的基本类型,也支持集合和自定义类型,为开发过程中的默认值管理提供了一个简单且高效的解决方案。
四、附上代码
package com.pilot.meterage.web.utils;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 默认值工具类
*
* @Author: yangp
* @Date: 2024/12/3 上午11:19
* @Version 2.0
* @Description 封装了一些常用默认值处理方法
*/
@Slf4j
public class DefaultUtil {
private static final Map<Class<?>, Object> PRIMITIVE_DEFAULTS;
private static final Consumer<String> LOG_INFO = message -> log.info("[INFO] {}", message);
private static final BiConsumer<String, Throwable> LOG_ERROR = (message, throwable) -> log.error("[ERROR] {} ", message, throwable);
// 静态代码块,初始化常见基本类型和引用数据类型的默认值
static {
PRIMITIVE_DEFAULTS = Stream.of(
new AbstractMap.SimpleEntry<>(int.class, 0),
new AbstractMap.SimpleEntry<>(Integer.class, 0),
new AbstractMap.SimpleEntry<>(long.class, 0L),
new AbstractMap.SimpleEntry<>(Long.class, 0L),
new AbstractMap.SimpleEntry<>(double.class, 0.0),
new AbstractMap.SimpleEntry<>(Double.class, 0.0),
new AbstractMap.SimpleEntry<>(float.class, 0.0f),
new AbstractMap.SimpleEntry<>(Float.class, 0.0f),
new AbstractMap.SimpleEntry<>(boolean.class, false),
new AbstractMap.SimpleEntry<>(Boolean.class, false),
new AbstractMap.SimpleEntry<>(char.class, '\u0000'),
new AbstractMap.SimpleEntry<>(Character.class, '\u0000'),
new AbstractMap.SimpleEntry<>(byte.class, (byte) 0),
new AbstractMap.SimpleEntry<>(Byte.class, (byte) 0),
new AbstractMap.SimpleEntry<>(short.class, (short) 0),
new AbstractMap.SimpleEntry<>(Short.class, (short) 0),
new AbstractMap.SimpleEntry<>(String.class, ""),
new AbstractMap.SimpleEntry<>(List.class, Collections.emptyList()),
new AbstractMap.SimpleEntry<>(Set.class, Collections.emptySet()),
new AbstractMap.SimpleEntry<>(Map.class, Collections.emptyMap()),
new AbstractMap.SimpleEntry<>(Optional.class, Optional.empty())
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
private DefaultUtil() {
}
/**
* 如果值为null,返回指定的默认值
*
* @param value 输入值
* @param defaultValue 默认值
* @param <T> 值的类型
* @return 输入值或默认值
*/
public static <T> T defaultIfNull(T value, T defaultValue) {
return Optional.ofNullable(value).orElse(defaultValue);
}
/**
* 如果值为null,根据类型返回默认值
*
* @param value 输入值
* @param clazz 类型
* @param <T> 值的类型
* @return 输入值或类型的默认值
*/
public static <T> T defaultIfNull(T value, Class<T> clazz) {
return Optional.ofNullable(value).orElseGet(() -> getDefaultValue(clazz));
}
/**
* 根据类型返回默认值
*
* @param clazz 类型
* @param <T> 值的类型
* @return 类型的默认值
*/
@SuppressWarnings("unchecked")
public static <T> T getDefaultValue(Class<T> clazz) {
if (clazz == null) {
return null;
}
// 如果是 Optional 类型,返回空 Optional
if (clazz.equals(Optional.class)) {
return (T) Optional.empty();
}
// 优先从已定义的默认值映射中查找
T defaultValue = (T) PRIMITIVE_DEFAULTS.get(clazz);
if (defaultValue != null) {
return defaultValue;
}
// 对于集合类型,创建空集合
if (Collection.class.isAssignableFrom(clazz)) {
return createEmptyCollection(clazz);
}
// 对于 Map 类型,创建空 Map
if (Map.class.isAssignableFrom(clazz)) {
return (T) Collections.emptyMap();
}
// 尝试通过反射创建对象
return createInstance(clazz);
}
/**
* 创建空集合(List, Set等)
*/
@SuppressWarnings("unchecked")
private static <T> T createEmptyCollection(Class<T> clazz) {
if (List.class.isAssignableFrom(clazz)) {
return (T) Collections.emptyList();
} else if (Set.class.isAssignableFrom(clazz)) {
return (T) Collections.emptySet();
}
return null;
}
/**
* 尝试通过反射创建对象实例
*
* @param clazz 类型
* @param <T> 对象类型
* @return 创建的对象或null
*/
private static <T> T createInstance(Class<T> clazz) {
try {
return clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
logError("Failed to create instance for class: " + clazz, e);
return null;
}
}
private static void logInfo(String message) {
LOG_INFO.accept(message);
}
@SuppressWarnings("unused")
private static void logError(String message) {
LOG_INFO.accept(message);
}
private static void logError(String message, Throwable throwable) {
LOG_ERROR.accept(message, throwable);
}
public static void main(String[] args) {
logInfo("Testing default value utility...");
// 测试基本类型和包装类型
logInfo("defaultInt = " + defaultIfNull(null, Integer.class));
logInfo("defaultDouble = " + defaultIfNull(null, Double.class));
logInfo("defaultLong = " + defaultIfNull(null, Long.class));
logInfo("defaultBoolean = " + defaultIfNull(null, Boolean.class));
logInfo("defaultChar = " + defaultIfNull(null, Character.class));
logInfo("defaultByte = " + defaultIfNull(null, Byte.class));
logInfo("defaultShort = " + defaultIfNull(null, Short.class));
logInfo("defaultFloat = " + defaultIfNull(null, Float.class));
logInfo("defaultString = " + defaultIfNull(null, String.class));
// 测试集合类型
logInfo("defaultList = " + defaultIfNull(null, ArrayList.class));
logInfo("defaultSet = " + defaultIfNull(null, HashSet.class));
logInfo("defaultMap = " + defaultIfNull(null, HashMap.class));
logInfo("defaultOptional = " + defaultIfNull(null, Optional.class));
// 测试引用类型
logInfo("defaultString = " + defaultIfNull(null, "Hello"));
// 自定义类型
logInfo("defaultCustomType = " + defaultIfNull(null, CustomType.class));
// 测试 null 值
logInfo("nullValue = " + defaultIfNull(null, null));
logInfo("Testing finished.");
}
@Data
static class CustomType {
private String name;
}
}