[英]How can I avoid repeating code initializing a hashmap of hashmap?
Every client has an id, and many invoices, with dates, stored as Hashmap of clients by id, of a hashmap of invoices by date:每个客户都有一个 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 solution seems to be to use getOrDefault
: Java 解决方案似乎是使用
getOrDefault
:
HashMap<LocalDateTime, Invoice> allInvoices = allInvoicesAllClients.getOrDefault(
id,
new HashMap<LocalDateTime, Invoice> (){{ put(date, invoice); }}
);
But if get is not null, I still want put (date, invoice) to execute, and also adding data to "allInvoicesAllClients" is still needed.但是如果 get 不为空,我仍然希望 put (date, invoice) 执行,并且仍然需要向“allInvoicesAllClients”添加数据。 So it doesn't seem to help much.
所以它似乎没有多大帮助。
This is an excellent use-case for Map#computeIfAbsent
.这是
Map#computeIfAbsent
一个很好的用例。 Your snippet is essentially equivalent to:您的代码段本质上等同于:
allInvoicesAllClients.computeIfAbsent(id, key -> new HashMap<>()).put(date, invoice);
If id
isn't present as a key in allInvoicesAllClients
, then it'll create mapping from id
to a new HashMap
and return the new HashMap
.如果
id
没有作为allInvoicesAllClients
的键allInvoicesAllClients
,那么它将创建从id
到新HashMap
映射并返回新的HashMap
。 If id
is present as a key, then it'll return the existing HashMap
.如果
id
作为键存在,那么它将返回现有的HashMap
。
computeIfAbsent
is a great solution for this particular case.对于这种特殊情况,
computeIfAbsent
是一个很好的解决方案。 In general, I'd like to note the following, since nobody mentioned it yet:总的来说,我想注意以下几点,因为还没有人提到它:
The "outer" hashmap just stores a reference to the "inner" hashmap, so you can just reorder the operations to avoid the code duplication: “外部”哈希映射仅存储对“内部”哈希映射的引用,因此您可以重新排序操作以避免代码重复:
HashMap<LocalDateTime, Invoice> allInvoices = allInvoicesAllClients.get(id);
if (allInvoices == null) {
allInvoices = new HashMap<>();
allInvoicesAllClients.put(id, allInvoices);
}
allInvoices.put(date, invoice); // <--- no longer repeated
You should pretty much never use "double brace" map initialization.您几乎不应该使用“双括号”映射初始化。
{{ put(date, invoice); }}
In this case, you should use computeIfAbsent
在这种情况下,您应该使用
computeIfAbsent
allInvoicesAllClients.computeIfAbsent(id, (k) -> new HashMap<>())
.put(date, allInvoices);
If there is no map for this ID, you will insert one.如果此 ID 没有映射,您将插入一个。 The result will be the existing or computed map.
结果将是现有的或计算出的地图。 You can then
put
items in that map with guarantee that it won't be null.然后,您可以
put
项目放入该地图中,并保证它不会为空。
This is longer than the other answers, but imho far more readable:这比其他答案更长,但恕我直言更具可读性:
if(!allInvoicesAllClients.containsKey(id))
allInvoicesAllClients.put(id, new HashMap<LocalDateTime, Invoice>());
allInvoicesAllClients.get(id).put(date, invoice);
You are doing two separate things here: ensuring that the HashMap
exists, and adding the new entry to it.您在这里做两件单独的事情:确保
HashMap
存在,并向其中添加新条目。
The existing code makes sure to insert the new element first before registering the hash map, but that isn't necessary, because the HashMap
doesn't care about the ordering here.现有代码确保在注册哈希映射之前先插入新元素,但这不是必需的,因为
HashMap
不关心这里的排序。 Neither variant is threadsafe, so you're not losing anything.这两个变体都不是线程安全的,因此您不会丢失任何东西。
So, like @Heinzi suggested, you can just split these two steps.因此,就像@Heinzi 建议的那样,您可以将这两个步骤分开。
What I would also do is offload the creation of the HashMap
to the allInvoicesAllClients
object, so the get
method cannot return null
.我还会做的是将
HashMap
的创建卸载到allInvoicesAllClients
对象,因此get
方法不能返回null
。
This also reduces the possibility for races between separate threads that could both get null
pointers from get
and then decide to put
a new HashMap
with a single entry -- the second put
would probably discard the first, losing the Invoice
object.这也减少了单独线程之间竞争的可能性,这些线程既可以从
get
获取null
指针,然后又决定put
一个新的HashMap
put
单个条目——第二个put
可能会丢弃第一个,从而丢失Invoice
对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.