如何编写 Null-Safety 代码?一文帮你讲透!
嗨,你好啊,我是猿java
NullPointerExceptions(NPE)空指针异常应该是每个程序员的噩梦,作为 Java 程序员都知道: NPE 是运行时异常,在代码编译过程中很难发现这种异常。因此,这篇文章,我们将分析如何编写 null 安全代码。
在实际工作中,对于 null的处理通常有以下处理方式:
- Nullable注解
- NonNull注解
- 显示处理 null
- 使用 Optional类
- 使用断言
- 编写清晰的文档
Nullable注解
@Nullable
是 Spring 的内置注解,可用于方法、参数或字段级别,用于标记方法的返回值或参数或字段可以为 null,通过使用 @Nullable
注解,开发者可以明确地表明某个方法可能返回 null 值,从而在调用该方法时更加谨慎。
如下示例:
1 | // 示例1:用于方法 |
在上述的示例中,@Nullable
用于方法,字段,参数,标识可以为 null,因此,方法的调用用就需要根据业务判断 null。
NonNull注解
@NonNull
是 Spring 的内置注解,可用于方法、参数或字段级别,用于标记方法的返回值或参数或字段不能为 null。通过使用 @NonNull
注解,开发者可以明确地表明某个方法不会返回 null 值,从而在调用该方法时可以放心地使用返回值。
如下示例:
1 | import org.springframework.lang.NonNull; |
在上述的示例中:
- 示例1,
@NonNull
注解标记方法其返回值不能为 null,因此,方法的调用者知道该方法不会返回 null 值,可以放心地使用返回值而不用担心空指针异常。 - 示例2,
@NonNull
注解标记方法的入参不能为 null - 示例3,
@NonNull
注解标记字段不能为 null,一旦字段值为 null,IDE会出现以下警告:
显式处理 null
显式处理 null应该是我们使用最多也是最灵活处理 null的方法,在编写代码时,要注意对可能为 null 的值进行显式的空值检查和处理,可以使用 if 语句、try-catch块等方式来处理空值情况,避免程序崩溃或数据丢失。
如下代码,针对 user 对象是否为 null 做不同的处理:
1 | // 方式1 |
使用 Optional类
Optional类是 Java 8 引入的,它的作用是封装一个可能为空的值,通过 Optional 类的方法,可以更加安全和优雅地处理空值情况,从而避免 NPE 空指针异常。
如下示例,针对上面手动处理 null, 我们可以使用 optional更优雅的实现 null 判断:
1 | Optional<User> userOptional = Optional.ofNullable(user); |
关于 Optional 更多的使用,参考下图:
使用 Optional 类的几个好处:
- 可以避免 NPE 空指针异常,提高代码的健壮性;
- 可以减少手动 null 判断,使代码更简洁和优雅;
- 符合函数式编程的特性;
使用断言
断言 assert 可以帮助发现潜在的空指针异常问题,确保代码的假设得到正确验证。
如下示例:
1 | assert user != null : "User object should not be null"; |
在上述示例中,我们使用断言来验证 user 对象不为 null,如果断言失败,则抛出相应的错误信息。
编写清晰的文档
在方法的注释中明确说明方法的返回值和参数是否可以为 null,以及如何处理 null情况。清晰的文档可以帮助其他开发者更好地理解代码逻辑和规范。
1 | /** |
上述示例中,我们编写了清晰的方法注释,明确说明了方法的返回值可能为 null,帮助其他开发者更好地理解方法的使用规范和处理空值情况。
注意事项
对于上述 Spring 的 @Nullable
和 @NonNull
注解,并非所有开发工具都能显示这些编译警告,如果未看到相关警告,请检查 IDE 中的编译器设置。这里以 IntelliJ 设置为例:
为了方便 IDE 进行一些自动化代码检查,我们可以使用 SpotBugs
提供了一个 插件,可以检测由于可为 null 性而导致的代码异味。
安装上述插件后,如果任何用 @NonNull
注释的方法意外返回 null,则 SpotBugs 检查将失败,并出现类似于以下内容的错误:
1 | [ERROR] High: xxx may return null, but is declared At xxx.java:[line 36] NP_NONNULL_RETURN_VIOLATION |
总结
本文,我们总结了对 null处理的几种通常方式:
- Nullable注解
- NonNull注解
- 显示处理 null
- 使用 Optional类
- 使用断言
- 编写清晰的文档
功夫在平常,功夫在细节!只要我们在日常开发中多注意一点细节,让好习惯成为自然,终有一天,不但可以写出让人羡慕的优雅代码,还可以写出高质量的代码。
学习交流
如果你觉得文章有帮助,请帮忙转发给更多的好友,或关注公众号:猿java,持续输出硬核文章。
![drawing](/images/pub.jpg)