Todo cliente tem um ID e muitas faturas, com datas, armazenadas como Hashmap de clientes por ID, de um hashmap de faturas por data:
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);
}
A solução Java parece usar getOrDefault
:
HashMap<LocalDateTime, Invoice> allInvoices = allInvoicesAllClients.getOrDefault(
id,
new HashMap<LocalDateTime, Invoice> (){{ put(date, invoice); }}
);
Mas se get não for nulo, eu ainda quero que a execução da data (fatura) seja executada, e também é necessário adicionar dados a "allInvoicesAllClients". Portanto, isso não parece ajudar muito.
Respostas:
Este é um excelente caso de uso para
Map#computeIfAbsent
. Seu snippet é essencialmente equivalente a:Se
id
não estiver presente como chaveallInvoicesAllClients
, ele criará o mapeamento deid
para um novoHashMap
e retornará o novoHashMap
. Seid
estiver presente como chave, retornará o existenteHashMap
.fonte
allInvoicesAllClients.computeIfAbsent(id, key -> Map.of(date, invoice))
Map.of
cria um modificávelMap
, que não tenho certeza se o OP deseja.computeIfAbsent
é uma ótima solução para este caso em particular. Em geral, gostaria de observar o seguinte, já que ninguém o mencionou ainda:O hashmap "externo" apenas armazena uma referência ao hashmap "interno", para que você possa reordenar as operações para evitar a duplicação de código:
fonte
computeIfAbsent()
método sofisticado !Você nunca deve usar a inicialização de mapa com "chave dupla".
Nesse caso, você deve usar
computeIfAbsent
Se não houver um mapa para esse ID, você inserirá um. O resultado será o mapa existente ou computado. Você pode então
put
itens nesse mapa com garantia de que não será nulo.fonte
id
está feito. Você pode pensarcomputeIfAbsent
em uma colocação condicional, se quiser. E também retorna o valor{{ }}
ter um significado especial, o que não acontece.Isso é mais longo que as outras respostas, mas é muito mais legível:
fonte
Você está fazendo duas coisas separadas aqui: garantir a existência
HashMap
e adicionar a nova entrada a ela.O código existente certifica-se de inserir o novo elemento primeiro antes de registrar o mapa de hash, mas isso não é necessário, porque
HashMap
ele não se importa com o pedido aqui. Nenhuma das variantes é segura para threads, portanto você não está perdendo nada.Então, como o @Heinzi sugeriu, você pode dividir essas duas etapas.
O que eu também faria é descarregar a criação de
HashMap
para oallInvoicesAllClients
objeto, para que oget
método não possa retornarnull
.Isso também reduz a possibilidade de corridas entre segmentos separados, que poderiam obter
null
ponteirosget
e decidirput
um novoHashMap
com uma única entrada - a segundaput
provavelmente descartaria a primeira, perdendo oInvoice
objeto.fonte