I was unable to find any issue or discussion related to what I described below and so decided to create a ticket.

After change 73e382fa877f80994817a136b0adcc4365ccd904 `LocalCache` implements its own versions of methods like `computeIfAbsent` and `computeIfPresent`. These replace previous implementations inherited from `ConcurrentMap` with ones that delegate to unconditional call to `compute` with customised lambda e.g. `computeIfAbsent`:

```java
 return ((v = get(key)) == null &&
                (newValue = mappingFunction.apply(key)) != null &&
                (v = putIfAbsent(key, newValue)) == null) ? newValue : v;
```
becomes:

```java
compute(key, (k, oldValue) -> (oldValue == null) ? function.apply(key) : oldValue);
```

This has side effect that even if value is already present it is replaced by itself which confuses removal listener that will report value being removed with `RemovalCause.REPLACED`. Stats are possibly also incorrect (not used them to date so I am not sure).

Below test case reproduces this behaviour.

```java
List<RemovalNotification> notifications = new ArrayList<>();

Cache<Integer, Integer> cache = CacheBuilder.<Integer, Integer>newBuilder()
        .removalListener((RemovalListener<Integer, Integer>) notifications::add)
        .recordStats()
        .build();

cache.asMap().computeIfAbsent(1, integer -> integer + 1);
cache.asMap().computeIfAbsent(1, integer -> integer + 1);

assert notifications.size() == 1;
assert notifications.get(0).getCause() == RemovalCause.REPLACED;
assert cache.stats().evictionCount() == 0;
assert cache.stats().loadCount() == 2;
```
}
  public void testPutCausesExpansion() {
    for (int count = 1; count <= 100; count++) {
      LocalCache<Object, Object> map =
          makeLocalCache(createCacheBuilder().concurrencyLevel(1).initialCapacity(1));
      Segment<Object, Object> segment = map.segments[0];
      assertEquals(1, segment.table.length());
      for (int i = 0; i < count; i++) {
        Object key = new Object();
        Object value = new Object();
        segment.put(key, key.hashCode(), value, true);
      }
      assertEquals(count, segment.count);
      assertTrue(count <= segment.threshold);
      assertTrue(count <= (segment.table.length() * 3 / 4));
      assertTrue(count > (segment.table.length() * 3 / 8));
    }
  }
  public void testReclaimKey() {
    CountingRemovalListener<Object, Object> listener = countingRemovalListener();
    LocalCache<Object, Object> map =
        makeLocalCache(
            createCacheBuilder()
                .concurrencyLevel(1)
                .initialCapacity(1)
                .maximumSize(SMALL_MAX_SIZE)
                .expireAfterWrite(99999, SECONDS)
                .removalListener(listener));
    Segment<Object, Object> segment = map.segments[0];
    AtomicReferenceArray<ReferenceEntry<Object, Object>> table = segment.table;