簡體   English   中英

java8 - 缺少變量和可選

[英]java8 - absent variable & Optional

我正在解析輸入JSON。 對於一個領域,有三種可能性:

  • 這個領域缺席;
  • 該值設置為null;
  • 該值設置為有效的值。

實現了不同的行為:對於JSON中缺少的值,將默認值插入到數據庫中; 對於JSON中的空值,將空值插入到數據庫中。

我想到了Optional模型:

public class Data {
    private Optional<String> field;
}

以下哪兩個選項最有意義?

  1. 如果field為null,則JSON中不存在該字段。 如果field為Optional.empty,則JSON中的字段為null
  2. 如果field為null,則JSON中的字段為null 如果field為Optional.empty,則JSON中不存在該字段。

FWIW,我使用Jackson和模塊jackson-datatype-jdk8來解析輸入JSON。

我認為你不應該在這種情況下使用Optional 正如@dkatzel在他的回答中所提到的,它意味着比作為字段更多地用作API返回值。

盡管進行了這方面的學術討論,但只需將Data類中的字段初始化為默認值即可實現您的目標:

public class Data {
    private String field = DEFAULT_VALUE;
}

然后讓傑克遜做其余的事情。


根據OP的評論編輯:

當您的JSON為field提供null值時,Jackson會將其設置為null ,這將存儲在數據庫中。

當您的JSON不包含該字段時, DEFAULT_VALUE將自動加載到您的Data實例中。

當你的JSON確實包含該field的值時,Jackson將設置它,並且該值將到達數據庫。


編輯2,考慮到OP要求在解析JSON輸入后找出field是填入,設置為null還是在輸入JSON中不存在的要求:

如果在解析輸入JSON之后 ,您需要知道該field是填充還是設置為null或不存在,那么請考慮這個示例,它顯示了我采用的方法:

public class Data {

    private String field1 = "hello";

    private Integer field2 = 10;

    private Double field3 = 3.75;

    private static final Data DEFAULTS = new Data(); // defaults will be kept here

    public String getField1() {
        return this.field1;
    }

    public void setField1(String field1) {
        this.field1 = field1;
    }

    public Integer getField2() {
        return this.field2;
    }

    public void setField2(Integer field2) {
        this.field2 = field2;
    }

    public Double getField3() {
        return this.field3;
    }

    public void setField3(Double field3) {
        this.field3 = field3;
    }

    @Override
    public String toString() {
        return "Data [field1=" + this.field1 + 
                   ", field2=" + this.field2 + 
                   ", field3=" + this.field3 + "]";
    }

    public boolean isDefault(Function<Data, Object> getter) {
        Object defaultProperty = getter.apply(DEFAULTS);
        Object actualProperty = getter.apply(this);
        return defaultProperty != null // needed to support fields with no default value
            && defaultProperty.equals(actualProperty);
    }

    public boolean isNull(Function<Data, Object> getter) {
        return getter.apply(this) == null;
    }

    public boolean isSet(Function<Data, Object> getter) {
        return !this.isNull(getter) && !this.isDefault(getter);
    }
}

在這里,我使用了一個private static屬性來保存Data的默認值和3個方法來查詢任何字段狀態(默認值,null或set)。 為了確定要查詢的字段,這些方法接收一個Function<Data, Object> ,它們被賦予一個Data實例並返回一個應該是所需字段的Object (如果你停下來想一想,可以將getter視為將實例作為輸入並返回實例的特定字段的函數)。

所以稍后,當你需要知道某個字段如何到達你的JSON輸入時,只需使用這3個查詢方法來找出:

ObjectMapper m = new ObjectMapper();

String json = "{\"field1\":null,\"field2\":20}";
Data data = m.readValue(json, Data.class);

System.out.println(data); // Data [field1=null, field2=20, field3=3.75]

System.out.println("field1 default ? " + data.isDefault(Data::getField1)); // false
System.out.println("field1 null ? " + data.isNull(Data::getField1)); // true
System.out.println("field1 set ? " + data.isSet(Data::getField1)); // false

System.out.println("field2 default ? " + data.isDefault(Data::getField2)); // false
System.out.println("field2 null ? " + data.isNull(Data::getField2)); // false
System.out.println("field2 set ? " + data.isSet(Data::getField2)); // true

System.out.println("field3 default ? " + data.isDefault(Data::getField3)); // true
System.out.println("field3 null ? " + data.isNull(Data::getField3)); // false
System.out.println("field3 set ? " + data.isSet(Data::getField3)); // false

我會說第一個選項具有最大的語義意義。 它還可能允許更容易的計算。

如果java中的字段為null,則表示缺少與第一個選項匹配的值。

我建議您將這些字段存儲在哈希映射中,其中鍵是JSON字段名稱,值是JSON字段的值。 我還建議你不要在這里使用一個可選項(因為它可以添加一個不必要的復雜層),而是在hashmap中使用null或非null對象。

HashMap<String, Value> jsonFields = new HashMap<String, Value>();
boolean hasField1 = false;
Value field1Value = null;
if(jsonFields.contains("field1"){ // It is present in the JSON file
    field1Value = jsonFields.get("field1"); // "null" here would mean that the JSON field was set to "null"
    hasField1 = true;
}

第二種選擇對我來說更有意義。 null表示null ,empty表示不存在。

但是, Optional不應該真正用作字段。 它應該被用作API返回值

您可以將數據存儲在允許空值的Map中嗎? 如果地圖中沒有關鍵字(您的字段),則返回Optional.empty

都不是? 我會用@DefaultValue()注釋我的POJO字段。 然后,您的可能性是在JSON中指定的空值或非空值,或者如果從JSON中省略該字段,則為默認值。 然后,您可以在沒有任何特殊的每場分析的情況下堅持POJO。

如果您正在處理Object而不是String ,那么這是一個我覺得優雅的解決方案:

  • 使用Optional.empty(); 如果沒有價值
  • 如果有Optional.of(value)使用Optional.of(value)
  • 如果值為null,請使用Optional.of(specialValue)

其中specialValue是一個靜態單例,你可以輕松測試,例如: ObjectUtils.NULL (來自commons.lang )。

然后你可以輕松測試你的可選:

if (optional.isPresent()) {
    if (ObjectUtils.NULL.equals(optional.get())) {
        // value is there and null
    } else {
        // value is there and not null
    }
} else {
    // value is not there 
}

暫無
暫無

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

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