Spring空安全注解

2023/05/12

1. 概述

从Spring 5开始,我们现在可以使用一个有趣的功能来帮助我们编写更安全的代码。 此功能称为null-safety,一组注解起到了保护作用,可以监视潜在的null引用。

null-safety特性并没有让我们摆脱不安全的代码,而是在编译时产生警告。此类警告可能会在运行时防止灾难性的空指针异常(NPE)。

2. @NonNull注解

@NonNull注解是null-safety特性的所有注解中最重要的注解。 我们可以在任何需要对象引用的地方使用这个注解声明非空约束:字段、方法参数或方法的返回值。

假设我们有一个名为Person的类:

public class Person {
    private String fullName;

    void setFullName(String fullName) {
        if (fullName != null && fullName.isEmpty()) {
            fullName = null;
        }
        this.fullName = fullName;
    }
    // getter
}

这个类定义是有效的,但是有一个缺陷,fullName字段可能被设置为null。如果发生这种情况,我们在使用fullName时可能会遇到NPE。

Spring null-safety特性使工具能够报告这种危险。例如,如果我们在IntelliJ IDEA中编写代码并使用@NonNull注解标注fullName字段, 我们将看到一个警告:

多亏这个提示,我们可以提前知道问题并能够采取适当的措施来避免运行时故障。

3. @NonNullFields注解

@NonNull注解有助于保证noll-safety安全。但是,如果使用此注解标注所有非空字段,我们的代码可能会变得非常臃肿。

为此我们可以通过另一个注解@NonNullFields来避免@NonNull的泛滥。 此注解适用于包级别,通知我们的开发工具,注解包中的所有字段默认为非null

要启用@NonNullFields注解,我们需要在包的根目录中创建一个名为package-info.java的文件,并使用@NonNullFields标注该包:

@NonNullFields
package cn.tuyucheng.taketoday.nullibility;

让我们在Person类中声明另一个属性,称为nickName:

package cn.tuyucheng.taketoday.spring.nullibility;

public class Person {
    private String nickName;

    void setNickName(@Nullable String nickName) {
        if (nickName != null && nickName.isEmpty()) {
            nickName = null;
        }
        this.nickName = nickName;
    }
    // other declarations
}

这一次,我们没有用@NonNull修饰nickName字段,但仍然看到类似的警告:

@NonNullFields注解使我们的代码不那么冗长,同时确保与@NonNull提供的安全级别相同。

4. @Nullable注解

@NonNullFields注解通常比@NonNull更可取,因为它有助于减少样板代码。有时我们希望从包级别指定的非空约束中免除某些字段。

让我们回到nickName字段并用@Nullable注解修饰它:

@Nullable
private String nickName;

我们以前看到的警告现在已经消失了:

在这种情况下,我们使用@Nullable注解来覆盖字段上@NonNullFields的语义

5. @NonNullApi注解

顾名思义,@NonNullFields注解仅适用于字段。如果我们想对方法的参数和返回值产生同样的影响,我们需要@NonNullApi

与@NonNullFields一样,我们必须在package-info.java文件中指定@NonNullApi注解:

@NonNullApi
@NonNullFields
package cn.tuyucheng.taketoday.spring.nullibility;

让我们为nickName字段定义一个getter方法:

package cn.tuyucheng.taketoday.spring.nullibility;

public class Person {
    @Nullable
    private String nickName;

    String getNickName() {
        return nickName;
    }
    // other declarations
}

在@NonNullApi注解生效的情况下,会产生一条警告,提示getNickName()方法可能产生空值:

请注意,就像@NonNullFields注解一样,我们可以在方法级别使用@Nullable注解覆盖@NonNullApi。

6. 总结

Spring null-safety是一个很棒的特性,它有助于减少NPE的可能性。但是,在使用此功能时,我们需要注意两点:

  • 它只能在支持的开发工具中使用,例如IntelliJ IDEA。
  • 它不会在运行时强制执行空检查,我们仍然需要自己编写代码来避免NPE。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章