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
idno está presente como claveallInvoicesAllClients, creará una asignación deiduna nuevaHashMapy devolverá la nuevaHashMap. Siidestá presente como una clave, devolverá la existenteHashMap.fuente
allInvoicesAllClients.computeIfAbsent(id, key -> Map.of(date, invoice))Map.ofcrea un inmodificableMap, que no estoy seguro de que el OP quiera.computeIfAbsentEs 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
computeIfAbsentSi no hay un mapa para esta ID, insertará uno. El resultado será el mapa existente o calculado. A continuación, puede
putelementos en ese mapa con la garantía de que no será nulo.fuente
idestá hecho también. Puede pensarcomputeIfAbsentcomo 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
HashMapexista 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
HashMapque 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
HashMapalallInvoicesAllClientsobjeto, por lo que elgetmétodo no puede volvernull.Esto también reduce la posibilidad de carreras entre hilos separados que podrían obtener
nullpunterosgety luego decidirputuna nuevaHashMapcon una sola entrada: la segundaputprobablemente descartaría a la primera, perdiendo elInvoiceobjeto.fuente