关键在于工具类内部做防御性校验与默认兜底:必填参数用objects.requirenonnull校验,可选参数提供线程安全默认值,禁止null成员赋值,推荐局部变量传参或supplier延迟获取,泛型+工厂方法提升类型安全。

关键在于:不依赖调用方保证对象非空,而是在工具类内部做防御性校验与默认兜底,同时保持接口语义清晰、行为可预测。
明确参数契约并强制校验
所有共享对象参数必须在方法入口处立即校验,不留给后续逻辑“侥幸运行”的空间。使用 Objects.requireNonNull() 抛出带业务上下文的 NullPointerException,比 NPE 堆栈更易定位问题。
- 对必填共享对象(如回调处理器、配置容器、上下文快照)直接校验:Objects.requireNonNull(config, "config must not be null")
- 对可选共享对象(如 MDC 快照、TraceContext),接受 null 但需主动初始化默认值,而非放任 null 向下传递
- 避免在 if (obj == null) 分支里延迟初始化——这容易遗漏同步控制,导致多个线程重复构造或状态不一致
提供安全的默认构造与懒加载策略
当传入对象为 null 时,不应直接报错退出,而是按场景提供合理默认行为。重点是默认值本身必须线程安全且无副作用。
- 用 ConcurrentHashMap.newKeySet() 替代 new HashSet() 作为默认集合参数
- 用 ThreadLocal.withInitial(() -> new Context()) 初始化隔离上下文,而非 new Context() 全局单例
- 对函数式参数(如 BiConsumer
),提供 NoOp 实现:BiConsumer.noop()(自定义静态方法),避免空指针或条件分支污染主流程
封装共享对象生命周期管理
高并发工具类常复用线程或跨请求共享对象(如连接池、缓存客户端)。未初始化的参数若被误存为实例字段,极易引发上下文污染或内存泄漏。
- 禁止将传入的共享对象直接赋值给类成员变量——除非你明确承担其线程安全责任
- 推荐用局部变量 + 显式传参方式流转,或通过 Supplier
延迟获取,确保每次调用都拿到新鲜/校验后的实例 - 若确需缓存(如共享序列化器),使用 final 字段 + 构造时一次性注入,拒绝运行时 setXXX(null) 类操作
用泛型约束 + 工厂方法提升类型安全性
避免 Object 或原始引用类型接收共享对象,改用泛型限定和专用构建器,把校验前移到编译期或构造阶段。
- 定义
Builder withConfig(C config) ,让 IDE 和编译器协助拦截非法类型 - 提供静态工厂方法如 HighConcUtil.of(config).withRetryPolicy(policy),构造即校验,返回不可变实例
- 对关键对象(如线程池、事件总线)要求实现 NonNullAware 接口,强制声明自身初始化状态











