簡體   English   中英

在JAVA中檢查對象的空字段

[英]Checking null fields of an object in JAVA

假設我有一個x字段的對象。 允許兩個非空,其余的必須為null。 我不想逐字段進行空檢查,所以我想知道是否有一種聰明的方法來使用最新的java版本的一些功能進行空檢查。

我不想按字段進行空檢查

您可以避免自己編寫支票,但必須“標記”字段上的約束。
為此,您可以使用Validator API( Hibernate 6提供默認實現的 JSR 380 )使用@Null@NotNull注釋您的類字段。

並使用Validator顯式驗證實例。
請注意,帶注釋的字段在上下文中可以是必需的null ,而在另一個上不一定是null 並且它與這種方式兼容,因為驗證器將僅在請求時驗證對象:即按需。


根據你的評論:

我正在開發代碼庫,您的解決方案是侵入性的。 我必須得到創建該pojo的低級json解析器。 我不想那樣做

在這種情況下,您可以使用要驗證的當前類的外部Map。
它將允許維護您驗證的字段的名稱,並在錯誤消息中使用它(對調試很有用)。

例如 :

Foo foo = new Foo();
// set foo fields...

// expected null but was not null
Map<String, Object> hasToBeNullMap = new HashMap<>();
hasToBeNullMap.put("x", foo.getX());
hasToBeNullMap.put("y", foo.getY());
hasToBeNullMap.put("z", foo.getZ());
String errrorMessageForNullExpected = getErrorFieldNames(hasToBeNullMap, Objects::nonNull);

// expected not null but was null
Map<String, Object> hasToBeNotNullMap = new HashMap<>();
hasToBeNotNullMap.put("z", foo.getZ());
String errrorMessageForNotNullExpected = getErrorFieldNames(hasToBeNotNullMap, o -> o == null);

private static String getErrorFieldNames(Map<String, Object> hasToBeNullMap, Predicate<Object> validationPred) {
    return hasToBeNullMap.entrySet()
                         .stream()
                         .filter(validationPred::test)
                         .map(Entry::getKey)
                         .collect(joining(","));
}

您可以為POJO中的所有字段創建stream ,並可以檢查null

return Stream.of(id, name).anyMatch(Objects::isNull);

要么

return Stream.of(id, name).allMatch(Objects::isNull);

如果對象中只有少數字段,並且您知道它不會經常更改,則可以根據Deadpool的答案將它們列為Stream.of參數。 缺點是違反DRY原則:您正在重復字段名稱:一次在POJO定義中,再次在參數列表中。

如果你有很多字段(或者不想重復自己),你可以使用反射:

boolean valid = Stream.of(YourPojoClass.class.getDeclaredFields())
    .filter(f -> !(f.getName().equals("fieldname allowed to be null") || f.getName.equals("the other field name")))
    .allMatch(f -> {
        f.setAccessible(true);
        try {
            return f.get(o) == null;
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    });

請注意,與解析從Web服務獲取的JSON字符串相比,使用反射可能會帶來很小的性能損失,這可能是微不足道的。

如果你有原始字段(例如intbooleanchar )並且你想將它們包含在支票中,將它們限制為默認值( 0false'\\0' ),那么使用以下代碼:

    .allMatch(f -> {
        f.setAccessible(true);
        try {
            return (f.getType() == boolean.class && f.getBoolean(o) == false)
                    || (f.getType().isPrimitive() && f.getDouble(o) == 0)
                    || f.get(o) == null;
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    });

什么時候你想要檢查? 最好的解決方案是創建一個不可變類,只提供1個構造函數。 不要添加setter。

private String name;
private String nickname;
// Rest of the fields with default (null) values
public Person(String name, String nickname) {
 this.name = name;
 this.nickname = nickname;
}
private Person(){}
// Getters, but no setters

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM