Jeder Kunde hat eine ID und viele Rechnungen mit Datumsangaben, die als Hashmap von Kunden nach ID gespeichert sind, sowie eine Hashmap von Rechnungen nach Datum:
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-Lösung scheint zu verwenden getOrDefault
:
HashMap<LocalDateTime, Invoice> allInvoices = allInvoicesAllClients.getOrDefault(
id,
new HashMap<LocalDateTime, Invoice> (){{ put(date, invoice); }}
);
Aber wenn get nicht null ist, möchte ich immer noch put (Datum, Rechnung) ausführen, und das Hinzufügen von Daten zu "allInvoicesAllClients" ist weiterhin erforderlich. Es scheint also nicht viel zu helfen.
Antworten:
Dies ist ein ausgezeichneter Anwendungsfall für
Map#computeIfAbsent
. Ihr Snippet entspricht im Wesentlichen:Wenn
id
es nicht als Schlüssel vorhanden istallInvoicesAllClients
, wird eine Zuordnung vonid
zu einer neuen erstelltHashMap
und die neue zurückgegebenHashMap
. Wennid
es als Schlüssel vorhanden ist, wird der vorhandene zurückgegebenHashMap
.quelle
allInvoicesAllClients.computeIfAbsent(id, key -> Map.of(date, invoice))
Map.of
erstellt eine nicht veränderbareMap
, die ich nicht sicher bin, ob das OP will.computeIfAbsent
ist eine großartige Lösung für diesen speziellen Fall. Im Allgemeinen möchte ich Folgendes beachten, da es noch niemand erwähnt hat:Die "äußere" Hashmap speichert nur einen Verweis auf die "innere" Hashmap, sodass Sie die Operationen einfach neu anordnen können, um die Codeduplizierung zu vermeiden:
quelle
computeIfAbsent()
Methode entwickelte!Sie sollten so gut wie nie die "Double Brace" -Karteninitialisierung verwenden.
In diesem Fall sollten Sie verwenden
computeIfAbsent
Wenn für diese ID keine Karte vorhanden ist, fügen Sie eine ein. Das Ergebnis ist die vorhandene oder berechnete Karte. Sie können dann
put
Elemente in dieser Karte mit der Garantie, dass sie nicht null sind.quelle
id
ist auch erledigt. Sie können sichcomputeIfAbsent
einen bedingten Put vorstellen, wenn Sie möchten. Und es gibt auch den Wert zurück{{ }}
eine besondere Bedeutung, die es nicht hat.Dies ist länger als die anderen Antworten, aber imho weitaus besser lesbar:
quelle
Sie machen hier zwei verschiedene Dinge: Sicherstellen, dass die
HashMap
vorhanden ist, und Hinzufügen des neuen Eintrags.Der vorhandene Code stellt sicher, dass das neue Element zuerst eingefügt wird, bevor die Hash-Map registriert wird. Dies ist jedoch nicht erforderlich, da die
HashMap
die Reihenfolge hier nicht wichtig ist. Keine der beiden Varianten ist threadsicher, sodass Sie nichts verlieren.Wie @Heinzi vorgeschlagen hat, können Sie diese beiden Schritte einfach aufteilen.
Was ich auch tun würde, ist die Erstellung des
HashMap
in dasallInvoicesAllClients
Objekt zu verlagern, so dass dieget
Methode nicht zurückkehren kannnull
.Dies verringert auch die Möglichkeit für Rennen zwischen separaten Threads, von denen beide
null
Zeiger abrufenget
und sich dann fürput
einen neuenHashMap
mit einem einzelnen Eintrag entscheiden könnten - der zweiteput
würde wahrscheinlich den ersten verwerfen und dasInvoice
Objekt verlieren .quelle