使用 @NotNull 注解进行非空校验

1、概览

空指针异常 NullPointerException 是一个常见问题,避免这种问题的方法之一是在方法参数上添加 @NotNull 等校验注解。

给方法参数添加了 @NotNull 注解后,还需要其他的一些设置才能自动对参数进行非空校验。

2、给方法参数添加 @NotNull 注解

创建一个类,其中包含一个返回 String 长度的方法。

String 参数上添加 @NotNull 注解:

public class NotNullMethodParameter {
    public int validateNotNull(@NotNull String data) {
        return data.length();
    }
}

注意,有多个包下都有 @NotNull 注解,我们使用的应该是 jakarta.validation.constraints 包。

创建 NotNullMethodParameter 实例,然后使用 null 参数调用方法。

NotNullMethodParameter notNullMethodParameter = new NotNullMethodParameter();
notNullMethodParameter.doesNotValidate(null);

尽管在参数上使用了 @NotNull,但还是出现了空指针异常:NullPointerException

注解未生效,因为没有 Validator 来执行它。

3、添加 Validator

添加 Hibernate Validator(jakarta.validation 的实现)来识别 @NotNull

<dependency> 
  <groupId>org.hibernate.validator</groupId> 
  <artifactId>hibernate-validator</artifactId> 
  <version>8.0.0.Final</version>
</dependency>

使用默认的 ValidatorFactory 创建 validator。

ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();

然后,在第一行验证参数。

validator.validate(myString);

现在,当调用参数是 null 时,@NotNull 校验注解就会生效。

java.lang.IllegalArgumentException: HV000116: The object to be validated must not be null.

这种校验方式存在一个问题,就是几乎要在所有的方法中手动调用 Validator 来对参数进行校验。

4、Spring Boot

如果是在 Spring Boot 应用中进行注解校验的话,一切就会变得简单多了。

4.1、Spring Boot Validation

首先,添加 spring-boot-starter-validation 依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
    <version>3.0.4</version>
</dependency>

先移除前面添加的 Hibernate依赖,因为 spring-boot-starter-validation 已经包含校验所需要的一切依赖。

现在,创建一个由 Spring 管理的组件,并添加 @Validated 注解。添加一个 validateNotNull 方法,该方法接收一个 String 参数并返回其长度,同时用 @NotNull 对参数进行注解:

@Component
@Validated
public class ValidatingComponent {
    public int validateNotNull(@NotNull String data) {
        return data.length();
    }
}

最后,创建一个 SpringBootTest,并注入 ValidatingComponent

添加一个测试方法,使 null 作为参数进行调用。

@SpringBootTest
class ValidatingComponentTest {
    @Autowired ValidatingComponent component;

    @Test
    void givenNull_whenValidate_thenConstraintViolationException() {
        assertThrows(ConstraintViolationException.class, () -> component.validate(null));
    }
}

校验生效,调用会失败,异常是:ConstraintViolationException

javax.validation.ConstraintViolationException: validate.data: must not be null

4.2、注意

如果你在同一个类中,通过 this 直接调用使用了校验注解的方法,校验不会生效(由于 Spring 的代理机制)。

如下:

public String callAnnotatedMethod(String data) {
    return validateNotNull(data);
}

这会直接导致 NullPointerException 异常。

4、总结

本文介绍了如何在 Java 中使用 @NotNull 注解来对参数进行非空校验,以及如何在 Spring Boot 中使用 @Validated 注解来简化 Spring Bean 方法参数的验证。


参考:https://www.baeldung.com/java-notnull-method-parameter