[英]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.