在方法參數上使用 @NotNull
一、概述
NullPointerException是一個常見問題。我們可以保護我們的代碼的一種方法是在我們的方法參數中添加諸如@NotNull之類的註釋。
通過使用NotNull ,我們表明如果我們想避免異常,我們絕不能使用null調用我們的方法。然而,就其本身而言,這還不夠。讓我們來了解一下原因。
2. 方法參數上的@NotNull註解
首先,讓我們創建一個具有簡單返回String長度的方法的類。
讓我們也為我們的參數添加一個@NotNull註解:
public class NotNullMethodParameter {
 public int validateNotNull(@NotNull String data) {
 return data.length();
 }
 }當我們導入NotNull, w我們應該注意@NotNull註釋有幾種實現。所以,我們需要確保它來自正確的包。
我們將使用javax.validation.constraints包。
現在,讓我們創建一個NotNullMethodParameter並使用null參數調用我們的方法:
NotNullMethodParameter notNullMethodParameter = new NotNullMethodParameter();
 notNullMethodParameter.doesNotValidate(null);儘管我們使用了NotNull註釋,但我們得到了NullPointerException :
java.lang.NullPointerException我們的註釋無效,因為沒有驗證器來強制執行它。
3. 添加驗證者
因此,讓我們添加 Hibernate Validator( javax.validation參考實現)來識別我們的@NotNull 。
除了我們的驗證器,我們還需要為它用於呈現消息的表達式語言 (EL) 添加一個依賴項:
<dependency>
 <groupId>org.hibernate.validator</groupId>
 <artifactId>hibernate-validator</artifactId>
 <version>6.2.3.Final</version>
 </dependency>
 <dependency>
 <groupId>org.glassfish</groupId>
 <artifactId>javax.el</artifactId>
 <version>3.0.0</version>
 </dependency>當我們不包含 EL 依賴項時,我們會收到一個ValidationException來提醒我們:
javax.validation.ValidationException: HV000183: Unable to initialize 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath, or use ParameterMessageInterpolator instead有了我們的依賴關係,我們可以強制執行我們的@NotNull註釋。
所以,讓我們使用默認的ValidatorFactory創建一個驗證器:
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
 Validator validator = factory.getValidator();然後,讓我們validate我們的論點作為我們帶註釋的方法的第一行:
validator.validate(myString);現在,當我們使用 null 參數調用我們的方法時,我們的@NotNull被強制執行:
java.lang.IllegalArgumentException: HV000116: The object to be validated must not be null.這很好,但是必須在每個帶註釋的方法中添加對我們的驗證器的調用會導致大量的樣板文件。
4. 彈簧靴
幸運的是,我們可以在 Spring Boot 應用程序中使用一種更簡單的方法。
4.1。春季啟動驗證
首先,讓我們添加 Maven 依賴項以使用 Spring Boot 進行驗證:
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-validation</artifactId>
 <version>2.7.1</version>
 </dependency>我們的spring-boot-starter-validation依賴項引入了 Spring Boot 和驗證所需的一切。這意味著我們可以刪除我們之前的 Hibernate 和 EL 依賴項以保持我們的pom.xml乾淨。
現在,讓我們創建一個 Spring 管理的Component ,確保我們添加了@Validated**註解**。讓我們使用validateNotNull方法創建它,該方法接受一個String參數並返回我們數據的長度,並使用NotNull註釋我們的參數:
@Component
 @Validated
 public class ValidatingComponent {
 public int validateNotNull(@NotNull String data) {
 return data.length();
 }
 }最後,讓我們使用自動裝配的ValidatingComponent創建一個SpringBootTest 。讓我們還添加一個帶有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.一個警告詞
雖然這適用於我們的public方法,但讓我們看看當我們添加另一個沒有註釋但調用原始註釋方法的方法時會發生什麼:
public String callAnnotatedMethod(String data) {
 return validateNotNull(data);
 }我們的NullPointerException返回。當我們從同一個類中的另一個方法調用帶註釋的方法時,Spring 不會強制執行NotNull約束。
4.3. Jakarta 和 Spring Boot 3.0
在 Jakarta 中,驗證包名稱最近從javax.validation更改為jakarta.validation 。 Spring Boot 3.0 基於 Jakarta ,因此使用較新的jakarta.validation包。從 7.0.* 及更高版本的hibernate-validator版本也是如此。這意味著當我們升級時,我們需要更改我們在驗證註釋中使用的包名稱。
5. 結論
在本文中,我們學習瞭如何在標準 Java 應用程序中對方法參數使用@NotNull註釋。我們還學習瞭如何使用 Spring Boot 的@Validated註解來簡化我們的 Spring Bean 方法參數驗證,同時也注意到它的局限性。最後,我們注意到當我們將 Spring Boot 項目更新到 3.0 時,我們應該期望將我們的javax包更改為jakarta 。
像往常一樣,本文中顯示的所有代碼示例都可以在 GitHub 上找到。