3

I want to apply a compute method that increment value if key exists, otherwise puts 1. Having

Map<Integer, Integer> map = new HashMap<>();

I don't understand why

for (int i = 0; i < 10; i++) map.compute(1, (k, v) -> v != null ? v++ : 1);

results in {1=1} and

for (int i = 0; i < 10; i++) map.compute(1, (k, v) -> (v != null ? v : 0) + 1);

results in {1=10}?

My understanding on first case is:

  • if there's a value with key k, get the result from v++ and put it back, else fill it with 1

While the seconds case is:

  • if there's a value with k k save v+1 instead, else save 0+1, which is also 1

Why in this case running v++ doesn't result in v+1?

Naman
  • 23,555
  • 22
  • 173
  • 290
rado
  • 2,150
  • 3
  • 24
  • 38

1 Answers1

5

Because (k, v) -> (v != null) ? v++ : 1 will always return 1 after the first iteration.

On the first iteration, v != null will evaluate to false and 1 will be mapped to key 1. On all subsequent calls, the condition will be true and v++ will be used, with the fact that post-increment v++ being in use, 1 will be the new mapped value all the time (and not 2).

v++ increments the local parameter of the lambda expression, NOT the value in the map (remember, Java is pass by value)

If you use ++v instead of v++, you'll get 10 too. This will work because the new mapped value is already incremented (unlike v++ which takes the value and then increments v)

(v != null ? v : 0) + 1, on the other hand, will always add 1 to the currently mapped value (it doesn't suffer from the behavior of v++)

ernest_k
  • 39,584
  • 5
  • 45
  • 86
  • 3
    Well, even simpler is `map.merge(key, 1, (a, b) -> a + b);` or `map.merge(key, 1, Integer::sum);` – Holger Dec 11 '20 at 16:44