如何在Java中停止检查null而不发疯

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

null的诅咒:为什么我们一遍又一遍地写同样的代码?

\n\n

如果你写Java超过一周,你肯定遇到过NullPointerException。而且,很可能你的第一反应是:“啊哈,只需要检查一下!”。于是,成千米的代码就这样诞生了:

\n\n
if (user != null) {\n    if (user.getAddress() != null) {\n        String city = user.getAddress().getCity();\n        if (city != null) {\n            System.out.println(city.toUpperCase());\n        }\n    }\n}\n
\n\n

这段代码能运行。但它很丑陋。它把阅读逻辑变成了一种折磨,把维护变成了噩梦。Stack Overflow上关于“How do I avoid checking for nulls in Java?”的问题获得了数千次浏览并非偶然。每个Java开发者迟早都会问自己这个问题。

\n\n

好消息是:避免null检查不仅可能,而且必要。Java不是JavaScript,我们有工具来编写干净、安全的代码,而无需“防御性”结构。让我们逐一分析它们——从基础工具到高级技术。

\n\n

1. Optional<T>——你的主要盟友

\n\n

从Java 8开始,我们有Optional。这是一个可以包含值或为空的容器。它的设计初衷就是为了避免null检查,并使代码更具声明性。

\n\n

它是如何工作的?

\n\n

与其从方法返回null,不如返回Optional。与其进行检查,不如使用方法链。

\n\n
// 糟糕的做法\npublic String getCity(User user) {\n    if (user == null) return "Unknown";\n    Address address = user.getAddress();\n    if (address == null) return "Unknown";\n    return address.getCity();\n}\n\n// 好的做法\npublic Optional<String> getCity(User user) {\n    return Optional.ofNullable(user)\n            .map(User::getAddress)\n            .map(Address::getCity);\n}\n\n// 使用\nString city = getCity(someUser).orElse("Unknown");\n
\n\n

注意:没有一个if。map仅在值不为null时工作。如果在任何阶段遇到null,链式调用就会中断,你会得到Optional.empty()。

\n\n

Optional的常用方法

\n\n
    \n
  • orElse(T other)——返回值或备用值
  • \n
  • orElseGet(Supplier<? extends T> other)——惰性版本,仅在需要时计算
  • \n
  • orElseThrow(Supplier<? extends X> exceptionSupplier)——抛出你自己的异常
  • \n
  • ifPresent(Consumer<? super T> consumer)——如果值存在则执行操作
  • \n
  • filter(Predicate<? super T> predicate)——根据条件过滤
  • \n
\n\n
// 带过滤器的示例\nOptional<String> name = Optional.of("Java");\nname.filter(n -> n.startsWith("J"))\n    .ifPresent(System.out::println); // 输出 "Java"\n
\n\n

重要提示:Optional用于返回值,而不是用于类的字段或方法的参数。不要滥用。

\n\n

2. Objects.requireNonNull()——用于显式约定的实用工具

\n\n

有时null是一个错误,需要尽早发现。与其手动编写检查,不如使用java.util.Objects.requireNonNull()。

\n\n
public class UserService {\n    private final UserRepository repository;\n\n    public UserService(UserRepository repository) {\n        this.repository = Objects.requireNonNull(repository, \n            "UserRepository must not be null");\n    }\n\n    public User findById(Long id) {\n        Objects.requireNonNull(id, "ID must not be null");\n        return repository.findById(id);\n    }\n}\n
\n\n

这种方法被称为

博客

书籍推荐