首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 與 C# 參數驗證最佳實踐:Guava Preconditions 與 FluentValidation

     編輯:Java 相關知識

參數驗證是防禦性編程核心。本文對比 Java (Guava Preconditions) 與 C# (FluentValidation) 兩大生態主流驗證庫,展示聲明式驗證、異常信息攜帶、複雜規則組合、單元測試友好等最佳實踐。

Java:Guava Preconditions — 輕量級防禦性檢查

Maven 依賴


<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>32.1.3-jre</version>
</dependency>

核心 API 速查

實戰代碼


import com.google.common.base.Preconditions;

public class UserService {
    public void register(String username, int age, String email) {
        // 1. 基礎非空/非空字符串
        Preconditions.checkNotNull(username, "用戶名不能為 null");
        Preconditions.checkArgument(!username.trim().isEmpty(), "用戶名不能為空");
        
        // 2. 範圍驗證
        Preconditions.checkArgument(age > 0 && age < 150, "年齡必須在 1-149 之間,實際:%s", age);
        
        // 3. 格式驗證 (正則)
        Preconditions.checkArgument(
            email.matches("^[\\w.-]+@[\\w.-]+\\.\\w+$"), 
            "郵箱格式不合法:%s", email
        );
        
        // 4. 業務規則驗證
        Preconditions.checkState(!userRepo.exists(username), "用戶名已存在:%s", username);
        
        // 通過驗證,執行業務邏輯
        userRepo.save(new User(username, age, email));
    }
}

優點與局限

  • ✅ 代碼極簡潔、可讀性強、零依賴侵入 (僅 Guava)。
  • ✅ 異常信息自帶參數值,除錯極其方便。
  • ✅ 適用於**方法入口防禦性檢查**、私有方法內部斷言。
  • ❌ 無分組驗證、無國際化、無註解聲明式綁定 (如 Bean Validation)。
  • ❌ 複雜對象圖驗證需手動遞歸調用。

C#:FluentValidation — 強大的聲明式驗證框架

NuGet 安裝


Install-Package FluentValidation
Install-Package FluentValidation.AspNetCore (ASP.NET Core 整合)

實體與驗證器分離


// 實體類 (POCO)
public class Person {
    public string Name { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }
    public Address Address { get; set; }
}

public class Address {
    public string City { get; set; }
    public string ZipCode { get; set; }
}

// 驗證器類 (繼承 AbstractValidator)
public class PersonValidator : AbstractValidator {
    public PersonValidator() {
        // 基礎規則
        RuleFor(x => x.Name)
            .NotEmpty().WithMessage("姓名不能為空")
            .Length(1, 50).WithMessage("姓名長度 1-50 字符");
        
        RuleFor(x => x.Age)
            .GreaterThan(0).WithMessage("年齡必須大於 0")
            .LessThan(150).WithMessage("年齡不能超過 150");
        
        RuleFor(x => x.Email)
            .NotEmpty().WithMessage("郵箱不能為空")
            .EmailAddress().WithMessage("郵箱格式不正確");
        
        // 嵌套對象驗證
        RuleFor(x => x.Address)
            .NotNull().WithMessage("地址不能為空")
            .SetValidator(new AddressValidator()); // 復用子驗證器
        
        // 條件驗證
        RuleFor(x => x.Email)
            .NotEmpty().When(x => x.Age >= 18).WithMessage("成年人必須提供郵箱");
        
        // 自定義驗證邏輯
        RuleFor(x => x.Name)
            .Must(BeUniqueName).WithMessage("姓名已被佔用");
    }

    private bool BeUniqueName(string name) {
        // 調用 Repository 檢查
        return !userRepo.Exists(name);
    }
}

public class AddressValidator : AbstractValidator
{ public AddressValidator() { RuleFor(x => x.City).NotEmpty(); RuleFor(x => x.ZipCode).Matches(@"^\d{6}$").WithMessage("郵編格式錯誤"); } }

使用方式


// 手動驗證
var person = new Person { Name = "", Age = -5, Email = "invalid" };
var validator = new PersonValidator();
var result = validator.Validate(person);

if (!result.IsValid) {
    foreach (var failure in result.Errors) {
        Console.WriteLine($"屬性: {failure.PropertyName}, 錯誤: {failure.ErrorMessage}");
    }
    // 輸出:
    // 屬性: Name, 錯誤: 姓名不能為空
    // 屬性: Age, 錯誤: 年齡必須大於 0
    // 屬性: Email, 錯誤: 郵箱格式不正確
}

// ASP.NET Core 自動驗證 (啟用後 Controller 參數自動驗證)
[ApiController]
public class UserController : ControllerBase {
    [HttpPost]
    public IActionResult Register([FromBody] Person person) {
        // ModelState.IsValid 自動檢查,失敗自動返回 400 + 錯誤詳情
        return Ok("註冊成功");
    }
}

進階特性

方法用途失敗拋出
checkArgument(boolean, msg, args...)驗證參數滿足條件IllegalArgumentException
checkNotNull(obj, msg, args...)驗證非 nullNullPointerException
checkState(boolean, msg, args...)驗證對象狀態 (非參數)IllegalStateException
checkElementIndex/PositionIndex驗證索引合法性IndexOutOfBoundsException
特性說明
規則集同一驗證器定義多組規則 (如 RuleSet("register")),按場景啟用
異步驗證MustAsync 支援 DB 查詢、外部 API 調用
屬性級依賴注入驗證器構造函數注入 Service/Repository
客戶端驗證生成ASP.NET Core 整合可輸出 jQuery Validation/Unobtrusive 規則
本地化WithMessage 支援資源文件鍵,配合 IStringLocalizer
測試輔助TestValidate 擴展方法單元測試極其方便

Java Bean Validation (JSR 380) — 企業級標準替代

若需註解聲明式、分組、國際化、Spring 整合,請用標準 Bean Validation:


@Entity
public class User {
    @NotNull @Size(min=2, max=20) private String username;
    @Min(1) @Max(120) private int age;
    @Email private String email;
    @Valid private Address address; // 級聯驗證
}

// Service 中
@Validated
public void register(@Valid User user) { ... }

// 全局異常處理
@ExceptionHandler(MethodArgumentNotValidException.class)
public R handleValidException(MethodArgumentNotValidException e) {
    return R.error(e.getBindingResult().getFieldErrors().stream()
        .map(fe -> fe.getField() + ": " + fe.getDefaultMessage())
        .collect(Collectors.joining("; ")));
}

選型建議

場景推薦方案理由
Java 簡單方法入口檢查Guava Preconditions零配置、極簡、異常信息豐富
Java 實體/DTO 結構化驗證Bean Validation (Hibernate Validator)標準註解、Spring 深度整合、分組/國際化
Java 複雜業務規則、異步驗證自定義 Validator + Spring Events完全可控、可注入服務
C# 實體驗證、ASP.NET Core 專案FluentValidation流式 API、規則集、異步、測試友好、客戶端生成
C# 簡單檢查Guard Clauses / ArgumentNullException.ThrowIfNull() (.NET 6+)內建、零依賴

總結

  1. **永遠在方法邊界驗證參數**,失敗快、信息全、易除錯。
  2. Java 輕量場景用 Guava,企業級標準用 Bean Validation。
  3. C# 首選 FluentValidation,功能最全、生態最強。
  4. 驗證邏輯與業務邏輯分離:驗證器類 / 註解 / 斷言,保持 Service 純淨。
  5. 異常信息**必須包含具體參數值**,避免「參數錯誤」這類無效日誌。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved