liveBook · Manning

Get/put sequence

As explained in 100 Java Mistakes and How to Avoid Them

A get/put sequence is a map-update pattern that separately retrieves a value and then inserts or updates a mapping.

A get/put sequence retrieves a mapping value, decides whether to create or update it, and then stores the result. It is a useful fallback when computeIfAbsent() would recursively modify the same map, but it is not atomic when multiple threads can update a concurrent map. section 8.12 section 9.12

Caching a recursively computed value

For a cache whose calculation calls the cache again, use a direct sequence: get the cached result; if absent, calculate it; put the result; return it. This avoids the ConcurrentModificationException that can arise when computeIfAbsent() indirectly modifies the same map. The sequence remains sensitive to call order in ordinary caching code, so tests should not rely on one traversal order. section 8.12

The concurrent-update trap

On a ConcurrentMap, reading a count and then writing the incremented count allows another thread to change the entry between calls, losing an update. Use merge(key, 1, Integer::sum) for this counting operation instead. section 9.12

Set<String> transitiveReferences(String variable) {
  Set<String> result = refCache.get(variable);
  if (result == null) {
    result = calc(variable);
    refCache.put(variable, result);
  }
  return result;
}

Shows the direct get/put cache sequence used instead of recursive computeIfAbsent(). section 8.12

void addValue(ConcurrentMap<String, Integer> map, String key) {
  map.merge(key, 1, Integer::sum);
}

Shows merge() replacing a non-atomic concurrent counting sequence. section 9.12

Avoid the pattern’s common failure modes:

  • Use get/put when a computeIfAbsent() function directly or indirectly modifies the same map. section 8.12
  • Use Map atomic operations such as merge(), compute(), or putIfAbsent() when concurrent updates must not lose changes. section 9.12
  • Recheck computeIfAbsent() behavior after Java upgrades; TreeMap changes in Java 15 can expose previously unnoticed misuse. section 8.12

How 100 Java Mistakes and How to Avoid Them covers it

How deep it goes
Explains call interleaving, recursive map modification, lost updates, and corrective APIs through focused Java snippets.
Examples
Uses recursive reference caching and concurrent occurrence counting to contrast direct get/put with computeIfAbsent() and merge().
What it assumes
Assumes Java Map usage and distinguishes ordinary map caching from concurrent-map atomicity.
What you can do after
Apply it via direct caching logic, or replace it with merge() and related atomic Map methods when threads share updates.
How it connects
Connects caching, computeIfAbsent(), concurrent collections, atomic operations, merge(), and test call-order dependence.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Java Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.