核心目标
该机制的核心目标就是通过在编译时进行静态代码检查,防止运行时抛出空指针异常。SpringBoot4.0默认集成JSpecify框架,支持使用JSpecify注解来声明API、字段及相关类型的可空性。
举个例子,现在有一个接口和实现类:
java
public interface TokenExtractorService {
String extractToken(String input);
}
@Service
public class TokenExtractorServiceImpl implements TokenExtractorService {
@Override
public String extractToken(String input) {
return input;
}
}
我们想要在编译期就能表达:入参不允许为null,返回允许为null,该如何来做呢?
可空性设置
我们可以使用@NonNull和@Nullable注解来说明这些类型的可空性。具体来说可以有两种方式,显式设置和隐式统一设置。
显式设置可空性
只需要在参数和返回上分别添加对应的注解即可:
java
public interface TokenExtractorService {
@Nullable String extractToken(@NonNull String input);
}
@Service
public class TokenExtractorServiceImpl implements TokenExtractorService {
@Override
public @Nullable String extractToken(@NonNull String input) {
return input;
}
}
@NonNull:不能为空@Nullable: 可以为空
加完这些标记以后,当我们调用这个方法的时候,IDEA就会有对应的错误提示:
java
@GetMapping("/demo")
public String demo(){
String token = tokenExtractorService.extractToken(null);
return token.toUpperCase();
}
以上代码,IDEA会给出2个警告:

隐式设置可空性
大多数情况下,我们一般默认这些参数、返回、字段、类型都是非空的,因此只需要明确的说明可空即可,因此我们还可以在包级别统一设置默认的可空性,这个可以借助package-info.java来实现。
首先在service包下面添加package-info.java:
java
@NullMarked
package com.github.xjs.service;
import org.jspecify.annotations.NullMarked;
@NullMarked:com.github.xjs.service这个包下面所有的参数、返回、字段、类型默认都是不允许为空@NullUnmarked:默认都允许为空,一般很少用
此时,就可以删除代码中的@NonNull注解,只保留@Nullable即可:
java
public interface TokenExtractorService {
@Nullable String extractToken(String input);
}
@Service
public class TokenExtractorServiceImpl implements TokenExtractorService {
@Override
public @Nullable String extractToken(String input) {
return input;
}
}
更多关于可空性的话题,比如:如何设置数组、泛型的可空性,如何与CI/CD集成,如何忽略告警,请参考:SpringBoot4.0新特性-Null-safety消灭空指针