簡體   English   中英

如何避免重復代碼初始化 hashmap 的 hashmap?

[英]How can I avoid repeating code initializing a hashmap of hashmap?

每個客戶都有一個 id 和許多帶有日期的發票,這些發票按 id 存儲為客戶的 Hashmap,按日期存儲為發票的哈希圖:

HashMap<LocalDateTime, Invoice> allInvoices = allInvoicesAllClients.get(id);

if(allInvoices!=null){
    allInvoices.put(date, invoice);      //<---REPEATED CODE
}else{
    allInvoices = new HashMap<>();
    allInvoices.put(date, invoice);      //<---REPEATED CODE
    allInvoicesAllClients.put(id, allInvoices);
}

Java 解決方案似乎是使用getOrDefault

HashMap<LocalDateTime, Invoice> allInvoices = allInvoicesAllClients.getOrDefault(
    id,
    new HashMap<LocalDateTime, Invoice> (){{  put(date, invoice); }}
);

但是如果 get 不為空,我仍然希望 put (date, invoice) 執行,並且仍然需要向“allInvoicesAllClients”添加數據。 所以它似乎沒有多大幫助。

這是Map#computeIfAbsent一個很好的用例。 您的代碼段本質上等同於:

allInvoicesAllClients.computeIfAbsent(id, key -> new HashMap<>()).put(date, invoice);

如果id沒有作為allInvoicesAllClients的鍵allInvoicesAllClients ,那么它將創建從id到新HashMap映射並返回新的HashMap 如果id作為鍵存在,那么它將返回現有的HashMap

對於這種特殊情況, computeIfAbsent是一個很好的解決方案。 總的來說,我想注意以下幾點,因為還沒有人提到它:

“外部”哈希映射僅存儲對“內部”哈希映射的引用,因此您可以重新排序操作以避免代碼重復:

HashMap<LocalDateTime, Invoice> allInvoices = allInvoicesAllClients.get(id);

if (allInvoices == null) {           
    allInvoices = new HashMap<>();
    allInvoicesAllClients.put(id, allInvoices);
}

allInvoices.put(date, invoice);      // <--- no longer repeated

您幾乎不應該使用“雙括號”映射初始化。

{{  put(date, invoice); }}

在這種情況下,您應該使用computeIfAbsent

allInvoicesAllClients.computeIfAbsent(id, (k) -> new HashMap<>())
                     .put(date, allInvoices);

如果此 ID 沒有映射,您將插入一個。 結果將是現有的或計算出的地圖。 然后,您可以put項目放入該地圖中,並保證它不會為空。

這比其他答案更長,但恕我直言更具可讀性:

if(!allInvoicesAllClients.containsKey(id))
    allInvoicesAllClients.put(id, new HashMap<LocalDateTime, Invoice>());

allInvoicesAllClients.get(id).put(date, invoice);

您在這里做兩件單獨的事情:確保HashMap存在,並向其中添加新條目。

現有代碼確保在注冊哈希映射之前先插入新元素,但這不是必需的,因為HashMap不關心這里的排序。 這兩個變體都不是線程安全的,因此您不會丟失任何東西。

因此,就像@Heinzi 建議的那樣,您可以將這兩個步驟分開。

我還會做的是將HashMap的創建卸載到allInvoicesAllClients對象,因此get方法不能返回null

這也減少了單獨線程之間競爭的可能性,這些線程既可以從get獲取null指針,然后又決定put一個新的HashMap put單個條目——第二個put可能會丟棄第一個,從而丟失Invoice對象。

暫無
暫無

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

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