Każdy klient ma identyfikator i wiele faktur, wraz z datami, przechowywanymi jako Hashmap klientów według identyfikatorów, skrótów faktur według dat:
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);
}
Wydaje się, że rozwiązaniem Java jest użycie getOrDefault
:
HashMap<LocalDateTime, Invoice> allInvoices = allInvoicesAllClients.getOrDefault(
id,
new HashMap<LocalDateTime, Invoice> (){{ put(date, invoice); }}
);
Ale jeśli get nie ma wartości zerowej, nadal chcę wykonać polecenie put (data, faktura), a także dodanie danych do „allInvoicesAllClients” jest nadal potrzebne. Więc to niewiele pomaga.
Odpowiedzi:
Jest to doskonały przypadek użycia dla
Map#computeIfAbsent
. Twój fragment kodu jest zasadniczo równoważny z:Jeśli
id
nie jest obecny jako kluczallInvoicesAllClients
, utworzy mapowanie zid
na nowyHashMap
i zwróci nowyHashMap
. Jeśliid
jest obecny jako klucz, wówczas zwróci istniejącyHashMap
.źródło
allInvoicesAllClients.computeIfAbsent(id, key -> Map.of(date, invoice))
Map.of
tworzy niemodyfikowalneMap
, czego nie jestem pewien OP chce.computeIfAbsent
jest doskonałym rozwiązaniem dla tego konkretnego przypadku. Ogólnie chciałbym zwrócić uwagę na następujące kwestie, ponieważ nikt jeszcze o tym nie wspominał:„Zewnętrzna” mapa skrótów po prostu przechowuje odniesienie do „wewnętrznej” tablicy skrótów, dzięki czemu można po prostu zmienić kolejność operacji, aby uniknąć powielania kodu:
źródło
computeIfAbsent()
metodą!Prawie nigdy nie powinieneś używać inicjalizacji mapy „podwójny nawias klamrowy”.
W takim przypadku powinieneś użyć
computeIfAbsent
Jeśli nie ma mapy dla tego identyfikatora, wstawisz ją. Wynikiem będzie istniejąca lub obliczona mapa. Możesz następnie
put
przedmioty na tej mapie z gwarancją, że nie będzie ona zerowa.źródło
id
gotowe jest również gotowe. Jeśli chcesz, możesz traktować tocomputeIfAbsent
jako warunkowe. I zwraca również wartość{{ }}
ma specjalne znaczenie, czego nie ma.Jest to dłuższe niż inne odpowiedzi, ale znacznie bardziej czytelne:
źródło
Robisz tutaj dwie oddzielne rzeczy: upewnienie się, że
HashMap
istnieje i dodanie do niej nowego wpisu.Istniejący kod upewnia się, że najpierw wstawisz nowy element przed zarejestrowaniem mapy skrótu, ale nie jest to konieczne, ponieważ tutaj
HashMap
nie zależy na zamówieniu. Żaden wariant nie jest bezpieczny dla wątków, więc nic nie tracisz.Tak jak sugerował @Heinzi, możesz po prostu podzielić te dwa kroki.
Co chciałbym także zrobić to odciążyć stworzenia
HashMap
doallInvoicesAllClients
obiektu, więcget
metoda ta nie może powrócićnull
.Zmniejsza to również możliwość wyścigów między osobnymi wątkami, które mogłyby zarówno pobrać
null
wskaźniki,get
a następnie zdecydować sięput
na nowyHashMap
z jednym wpisem - drugiput
prawdopodobnie odrzuciłby pierwszy, tracącInvoice
obiekt.źródło