| 註解 | 適用類型 | 校驗邏輯 | 空字符串 | 純空白字符串 |
|---|---|---|---|---|
| @NotNull | 任意類型 | 值 ≠ null | ✅ 通過 | ✅ 通過 |
| @NotEmpty | String、Collection、Map、Array | ≠ null 且 size/length > 0 | ❌ 失敗 | ✅ 通過 |
| @NotBlank | String | ≠ null 且 trim() 後 length > 0 | ❌ 失敗 | ❌ 失敗 |
/**
* The annotated element must not be {@code null}.
* Accepts any type.
*/
@Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE})
@Retention(RUNTIME)
public @interface NotNull { }
/**
* Asserts that the annotated string, collection, map or array
* is not {@code null} or empty.
*/
@Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE})
@Retention(RUNTIME)
public @interface NotEmpty { }
/**
* Validate that the annotated string is not {@code null} or empty.
* The difference to {@code NotEmpty} is that trailing whitespaces
* are getting ignored.
*/
@Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE})
@Retention(RUNTIME)
public @interface NotBlank { }
CharSequence.trim().length() > 0@NotNull private Long userId; // 外鍵 ID,不可為 null @NotBlank private String username; // 業務主鍵,不可為空白 @NotEmpty private List<String> tags; // 標籤集合,至少一個
@NotBlank(message = "手機號不能為空") private String phone; @NotBlank(message = "驗證碼不能為空") private String captcha; @NotEmpty(message = "至少選擇一個興趣標籤") private List<String> interests;
public class AddressDTO {
@NotBlank(message = "省份必填")
private String province;
@NotBlank(message = "城市必填")
private String city;
@NotEmpty(message = "詳細地址不能為空")
private String detail; // 允許空格但不可全空
}
@Target({FIELD, METHOD, PARAMETER})
@Retention(RUNTIME)
@NotNull
@NotBlank
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手機號格式錯誤")
public @interface ValidPhone {
String message() default "手機號格式錯誤";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
記住核心口訣:基本類型不用標,引用類型防 null 用 @NotNull;集合字符串防空用 @NotEmpty;字符串防空白必用 @NotBlank。正確選型能減少無效校驗代碼,提升 API 健壯性與可讀性。