本文目录导读:
- 使用 Optional(Java 8+ / Guava)
- 使用 Objects.requireNonNull / 断言(防御性编程)
- 使用 Apache Commons / Guava 工具类
- 使用 @Nullable / @NonNull 注解 + 静态分析(编译期消除)
- 使用空对象模式(Null Object Pattern)
- 使用流式 API 与
filter(Objects::nonNull)(处理集合) - 对于特定语言的语法糖
- 总结:如何选择?
“空判断”的冗余通常指代码中反复出现 if (xxx == null || xxx.isEmpty()) 或类似检查,并且这些检查的逻辑散落在各处。
核心优化的思路是:利用语言特性、设计模式、或类型系统,将“可能为空”这个状态,在更大范围内统一处理,而不是每次都单独判断。
以下是针对不同场景的 7 种具体优化策略:
使用 Optional(Java 8+ / Guava)
对于单一对象的链式调用,避免 null 检查的瀑布嵌套。
- 冗余代码:
if (user != null) { Address address = user.getAddress(); if (address != null) { String city = address.getCity(); if (city != null) { System.out.println(city.toUpperCase()); } } } - 优化后:
Optional.ofNullable(user) .map(User::getAddress) .map(Address::getCity) .ifPresent(city -> System.out.println(city.toUpperCase()));
使用 Objects.requireNonNull / 断言(防御性编程)
对于方法参数,如果空值本身就是非法的,应该在入口处明确抛出异常,而不是在内部多处判断。
- 冗余代码:
public void process(String name) { if (name == null) { throw new IllegalArgumentException("Name must not be null"); } // ... 后面再也不用担心 name 为 null } - 优化后(一种写法):
public void process(String name) { this.name = Objects.requireNonNull(name, "Name must not be null"); // 或直接调用方法而无需检查 }
使用 Apache Commons / Guava 工具类
对于字符串/集合,这些库提供了省去手动空判断的便捷方法。
- 冗余代码:
if (list != null && list.size() > 0) { // 处理 } if (str != null && !str.isEmpty()) { // 处理 } - 优化后:
if (CollectionUtils.isNotEmpty(list)) { // 处理 } if (StringUtils.isNotBlank(str)) { // 同时处理了 null 和空格 // 处理 }
使用 @Nullable / @NonNull 注解 + 静态分析(编译期消除)
在本地开发或代码审查阶段消灭空指针风险,运行时无需写 if 判断。
- 做法:在方法参数或返回值上标注注解,配合 IDE 或 Lint 工具检查。
public void setUser(@NotNull User user) { // IDE 会警告如果调用者传入 null } @NotNull public String getName() { return Objects.requireNonNull(name); }
使用空对象模式(Null Object Pattern)
对于返回值频繁为 null 的场景,返回一个无行为的默认对象,省去调用方的 null 判断。
- 冗余代码:
Log logger = getLogger(); if (logger != null) { logger.info("..."); } - 优化后:
// getLogger() 返回一个实现了 Logger 接口的 NullLogger 对象 // 内部所有方法为空实现(无操作) Log logger = getLogger(); // 保证不返回 null logger.info("..."); // 直接调用,无需判断
使用流式 API 与 filter(Objects::nonNull)(处理集合)
当你有一个集合,里面可能包含 null 元素,你需要处理非空元素时。
- 冗余代码:
for (String s : list) { if (s != null) { // 处理 s } } - 优化后:
list.stream() .filter(Objects::nonNull) .forEach(s -> { // 处理 s });
对于特定语言的语法糖
-
Kotlin:利用 (安全调用) 和 (Elvis 操作符) 消除冗余。
// 冗余写法: if (user != null) { println(user.name?.toUpperCase() ?: "UNKNOWN") } // 优化后: println(user?.name?.toUpperCase() ?: "UNKNOWN") -
TypeScript / JavaScript:利用可选链 和空值合并 。
// 冗余写法: const city = user && user.address && user.address.city ? user.address.city : 'Unknown'; // 优化后: const city = user?.address?.city ?? 'Unknown';
-
Python:利用
or短路或字典的.get方法。# 冗余写法: if config and 'key' in config and config['key'] is not None: value = config['key'] else: value = 'default' # 优化后: value = config.get('key') or 'default'
如何选择?
| 场景 | 最佳策略 |
|---|---|
| 链式调用 (user.getAddr().getCity()) | Optional / 可选链语法 |
| 方法参数 | Objects.requireNonNull / 断言 |
| 字符串集合判空 | Apache Commons / Guava 工具类 |
| 返回值可能为 null | 空对象模式 / Optional |
| 集合过滤 null 元素 | 流式 API + filter |
| 整个代码库空值泛滥 | 引入 @NonNull 注解 + 静态分析 |
| 使用现代语言 | 原生语法 (Kotlin , Dart , TS ) |
最根本的优化:不要返回 null,设计 API 时,优先返回空集合(Collections.emptyList())或空对象,而不是 null,这能从根源上减少 50% 以上的空判断。
标签: 代码冗余