Cada cliente tiene un id, y muchas facturas, con fechas, almacenadas como Hashmap de clientes por id, de un hashmap de facturas por fecha:
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);
}
La solución de Java parece ser usar getOrDefault
:
HashMap<LocalDateTime, Invoice> allInvoices = allInvoicesAllClients.getOrDefault(
id,
new HashMap<LocalDateTime, Invoice> (){{ put(date, invoice); }}
);
Pero si get no es nulo, todavía quiero que se ejecute put (fecha, factura), y también es necesario agregar datos a "allInvoicesAllClients". Por lo tanto, no parece ayudar mucho.
Respuestas:
Este es un excelente caso de uso para
Map#computeIfAbsent
. Su fragmento es esencialmente equivalente a:Si
id
no está presente como claveallInvoicesAllClients
, creará una asignación deid
una nuevaHashMap
y devolverá la nuevaHashMap
. Siid
está presente como una clave, devolverá la existenteHashMap
.fuente
allInvoicesAllClients.computeIfAbsent(id, key -> Map.of(date, invoice))
Map.of
crea un inmodificableMap
, que no estoy seguro de que el OP quiera.computeIfAbsent
Es una gran solución para este caso particular. En general, me gustaría señalar lo siguiente, ya que nadie lo mencionó todavía:El hashmap "externo" solo almacena una referencia al hashmap "interno", por lo que puede reordenar las operaciones para evitar la duplicación de código:
fuente
computeIfAbsent()
método elegante !Casi nunca deberías usar la inicialización del mapa de "doble paréntesis".
En este caso, debes usar
computeIfAbsent
Si no hay un mapa para esta ID, insertará uno. El resultado será el mapa existente o calculado. A continuación, puede
put
elementos en ese mapa con la garantía de que no será nulo.fuente
id
está hecho también. Puede pensarcomputeIfAbsent
como una opción condicional si lo desea. Y también devuelve el valor{{ }}
tiene un significado especial, que no es así.Esto es más largo que las otras respuestas, pero en mi opinión, mucho más legible:
fuente
Aquí está haciendo dos cosas separadas: asegurarse de que
HashMap
exista y agregarle la nueva entrada.El código existente se asegura de insertar el nuevo elemento primero antes de registrar el mapa hash, pero eso no es necesario, ya
HashMap
que no importa el orden aquí. Ninguna de las variantes es segura para subprocesos, por lo que no está perdiendo nada.Entonces, como sugirió @Heinzi, puede dividir estos dos pasos.
Lo que también haría es descargar la creación de la
HashMap
alallInvoicesAllClients
objeto, por lo que elget
método no puede volvernull
.Esto también reduce la posibilidad de carreras entre hilos separados que podrían obtener
null
punterosget
y luego decidirput
una nuevaHashMap
con una sola entrada: la segundaput
probablemente descartaría a la primera, perdiendo elInvoice
objeto.fuente