簡體   English   中英

如何避免 JSONObject Null 檢查

[英]How to avoid JSONObject Null check

我有 JSON 如下所示

{
  "a1": "aaa",
  "b1": 333,
  "c1": {
    "c1": "ccc",
    "d1": "ddd",
    "f1": [
      {"a1": "xyz"},
      {"b1":  "lmn"},
      {"c1":123.00}
    ]
  }
}

我正在將文件讀入 String 並創建一個 JSONObject 如下

JSONObject json = new JSONObject(new JSONTokener(str));

JSON 從外部進入我的應用程序,因此內容在時間上可能會有很大不同。 說它可以完全是 null 或者某些元素可以是 null 或者數組大小可以是 0 或 1 或更多等。

當我處理 JSONObject 時,我可以繼續使用檢查所有元素

json.has and !=null 

這樣它就不會拋出任何異常。

我可以有如下代碼

if(
      json.has("c") 
   && json.getJSONObject("c")!= null 
   && json.getJSONObject("c").has("f") 
   && json.getJSONObject("c").getJSONArray("f").length() > 1 
   &&json.getJSONObject("c").getJSONArray("f").getJSONObject(1).has("b")
  ){     
      String x = json.getJSONObject("c").getJSONArray("f").getJSONObject(1).getString("b");
   }

這使得代碼具有一長串 if 條件。

但是我在想,我可以用 try catch 來附上語句

try {
     String x = json.getJSONObject("c").getJSONArray("f").getJSONObject(1).getString("b");
    }catch(JSONException e) {
        //log and proceed
    }

請建議在這種情況下是否有任何正當理由放置一個較長的 if 條件,而不是僅僅嘗試 - 捕獲 - 記錄並繼續。

如果在這種情況下使用 JSONException 有任何“優點”,你也可以分享嗎?

選項 0:長 If 語句

我認為這太令人費解了,尤其是當鏈條變長時。 我會考慮遠程類似解決方案的唯一情況是,如果用戶需要確切地知道問題出在哪一點,並且有關於如何解決這個問題以及在非常具體的用例中如何發生這種情況的具體指導方針,但是在那個如果你需要大量的 if 語句和 log 語句。

選項 1:Try-Catch

正如您所建議的,Try-catch 確實是可能的,但是您需要確保捕獲在 JSON 字段不存在或類型錯誤時可能發生的所有異常,例如 ClassCastException 和 NullPointerException。 它很短但不是很優雅,正如其他回答者所說可能隱藏其他異常(但您仍然可以記錄堆棧跟蹤)。

選項2:Java 8 可選

另一種選擇是找到一個庫,允許您使用 Java 8 可選類型。 例如,建議使用Jackson 這更優雅,但也可以成為一個大鏈。 這也為您的項目增加了一個依賴項。

選項 3:路徑表達式

第三種選擇是使用路徑表達式JsonPath ,您可以將所有語句放入一個表達式中並獲得所有結果。 在我看來,這是一個完美的用例,也是迄今為止最好的解決方案。 唯一的缺點是這為您的項目增加了一個依賴項。

請建議在這種情況下是否有任何正當理由放置一個較長的 if 條件,而不是僅僅嘗試 - 捕獲 - 記錄並繼續。

這里有幾個原因:

  • 效率:創建、拋出和捕獲異常相對昂貴。 究竟有多昂貴取決於版本,也可能取決於上下文。 在最近的版本中,JIT 編譯器可以 (AFAIK) 將一些序列優化為條件分支。 但是,如果您要記錄異常,那么 JVM 將不得不創建異常 object 並填充堆棧跟蹤,這是最昂貴的部分。

  • 如果您將NullPointerException記錄為:

     json.getJSONObject("c").getJSONArray("f").getJSONObject(1).getString("b")

    可能無法分辨缺少哪些組件或 null。 堆棧跟蹤中的行號不足以區分這些情況。 (使用JSONException異常消息將為您提供更多線索。)

  • 您也無法區分jsonnull的情況,這可能是另一種問題; 即一個錯誤。 如果您將其視為數據錯誤,則很難找到和修復代碼錯誤。

  • 如果您捕獲所有異常(如另一個答案所建議的那樣),您可能會隱藏更多類別的錯誤。 餿主意。


如果在這種情況下使用 JSONException 有任何“優點”,你也可以分享嗎?

唯一真正的“優點”是它可能需要更少的代碼,特別是如果你可以嘗試...捕獲很多這樣的代碼。

最重要的是,您需要自己權衡一下。 一個因素是您獲得不符合您的代碼預期的 JSON 的可能性有多大。 這將部分取決於生產 JSON 的產品。

感謝上面的回復,下面是問題的解決方法。

JSONPath最適合我提到的場景。 感謝@Konrad。

首先創建一個 com.jayway.jsonpath.Configuration 類型的配置object

Configuration conf = Configuration.builder().options(Option.SUPPRESS_EXCEPTIONS).mappingProvider(new JsonOrgMappingProvider()).jsonProvider(new JsonOrgJsonProvider()).build();
  • Option.SUPPRESS_EXCEPTIONS - 這將有助於在缺少元素的情況下抑制異常
  • mappingProvider(new JsonOrgMappingProvider()).jsonProvider(new JsonOrgJsonProvider() - 這使用了正確的提供程序,因此當我們解析 json 時,我們不需要將 JSONObject 轉換為 String 從而提供最佳性能。
DocumentContext docContext = JsonPath.using(conf).parse(json);

如果我們使用默認提供程序,那么我們需要按如下方式解析 JSONObject

DocumentContext docContext = JsonPath.using(conf).parse(json.toString());

然后閱讀我使用的元素

docContext.read("$.a.b.c.d.values[0].e.f")

性能現在也是最佳的。 花費更多時間和 memory 的原因是因為

  • 我在一個循環中同時閱讀和解析。 后來我將解析移出循環。
  • 我正在使用默認提供程序並且正在執行 json.toString()

暫無
暫無

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

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