Pode ser um pouco tarde, mas aqui estão meus dois centavos.
Se você estiver usando o Java 8, poderá usar o método computeIfPresent . Se o valor da chave especificada estiver presente e não for nulo, ele tentará calcular um novo mapeamento, dada a chave e seu valor mapeado atual.
final Map<String,Integer> map1 = new HashMap<>();
map1.put("A",0);
map1.put("B",0);
map1.computeIfPresent("B",(k,v)->v+1); //[A=0, B=1]
Também podemos fazer uso de outro método putIfAbsent para colocar uma chave. Se a chave especificada ainda não estiver associada a um valor (ou estiver mapeada para nula), esse método a associará ao valor fornecido e retornará nulo; caso contrário, retornará o valor atual.
No caso do mapa é compartilhado entre threads, então podemos fazer uso de ConcurrentHashMap
e AtomicInteger . Do documento:
An AtomicInteger
é um valor int que pode ser atualizado atomicamente. Um AtomicInteger é usado em aplicativos como contadores incrementados atomicamente e não pode ser usado como um substituto para um número inteiro. No entanto, esta classe estende Number para permitir acesso uniforme por ferramentas e utilitários que lidam com classes numericamente baseadas.
Podemos usá-los como mostrado:
final Map<String,AtomicInteger> map2 = new ConcurrentHashMap<>();
map2.putIfAbsent("A",new AtomicInteger(0));
map2.putIfAbsent("B",new AtomicInteger(0)); //[A=0, B=0]
map2.get("B").incrementAndGet(); //[A=0, B=1]
Um ponto a observar é que estamos invocando get
para obter o valor da chave B
e, em seguida, invocando incrementAndGet()
seu valor, que é claro AtomicInteger
. Podemos otimizá-lo, pois o método putIfAbsent
retorna o valor da chave, se já estiver presente:
map2.putIfAbsent("B",new AtomicInteger(0)).incrementAndGet();//[A=0, B=2]
Além disso, se planejarmos usar o AtomicLong , conforme a documentação sob alta contenção, a taxa de transferência esperada do LongAdder será significativamente maior, à custa de um maior consumo de espaço. Verifique também esta pergunta .