Chaque client a un identifiant, et de nombreuses factures, avec des dates, stockées sous forme de Hashmap de clients par identifiant, d'un hashmap de factures par date:
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 solution Java semble être d'utiliser getOrDefault
:
HashMap<LocalDateTime, Invoice> allInvoices = allInvoicesAllClients.getOrDefault(
id,
new HashMap<LocalDateTime, Invoice> (){{ put(date, invoice); }}
);
Mais si get n'est pas nul, je veux toujours que put (date, facture) s'exécute, et l'ajout de données à "allInvoicesAllClients" est toujours nécessaire. Cela ne semble donc pas beaucoup aider.
Réponses:
C'est un excellent cas d'utilisation pour
Map#computeIfAbsent
. Votre extrait est essentiellement équivalent à:S'il
id
n'est pas présent en tant que cléallInvoicesAllClients
, il créera un mappage deid
vers un nouveauHashMap
et retournera le nouveauHashMap
. Siid
est présent sous forme de clé, il renverra l'existantHashMap
.la source
allInvoicesAllClients.computeIfAbsent(id, key -> Map.of(date, invoice))
Map.of
crée un élément non modifiableMap
, dont je ne suis pas sûr que l'OP le souhaite.computeIfAbsent
est une excellente solution pour ce cas particulier. En général, je voudrais noter ce qui suit, car personne ne l'a encore mentionné:La table de hachage "externe" stocke simplement une référence à la table de hachage "intérieure", vous pouvez donc simplement réorganiser les opérations pour éviter la duplication de code:
la source
computeIfAbsent()
méthode sophistiquée !Vous ne devriez pratiquement jamais utiliser l'initialisation de carte "double accolade".
Dans ce cas, vous devez utiliser
computeIfAbsent
S'il n'y a pas de carte pour cet ID, vous en insérerez une. Le résultat sera la carte existante ou calculée. Vous pouvez ensuite
put
ajouter des éléments dans cette carte avec la garantie qu'elle ne sera pas nulle.la source
id
est également fait. Vous pouvez pensercomputeIfAbsent
à un put conditionnel si vous le souhaitez. Et il renvoie également la valeur{{ }}
une signification particulière, ce qui n'est pas le cas.C'est plus long que les autres réponses, mais à mon humble avis beaucoup plus lisible:
la source
Vous faites deux choses distinctes ici: vous assurer que le
HashMap
existe et y ajouter la nouvelle entrée.Le code existant s'assure d'insérer le nouvel élément avant d'enregistrer la carte de hachage, mais ce n'est pas nécessaire, car le
HashMap
ne se soucie pas de l'ordre ici. Aucune des deux variantes n'est threadsafe, donc vous ne perdez rien.Ainsi, comme l'a suggéré @Heinzi, vous pouvez simplement diviser ces deux étapes.
Ce que je ferais aussi, c'est décharger la création de
HashMap
l'allInvoicesAllClients
objet vers l' objet, donc laget
méthode ne peut pas revenirnull
.Cela réduit également la possibilité de courses entre des threads séparés qui pourraient à la fois obtenir des
null
pointeursget
et ensuite décider d'put
une nouvelleHashMap
avec une seule entrée - la secondeput
rejetterait probablement la première, perdant l'Invoice
objet.la source