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;
```
static <K, V> void assertNotified(
      QueuingRemovalListener<K, V> listener, K key, V value, RemovalCause cause) {
    RemovalNotification<K, V> notification = listener.remove();
    assertSame(key, notification.getKey());
    assertSame(value, notification.getValue());
    assertSame(cause, notification.getCause());
  }
  
  public void testNewEntry() {
    for (CacheBuilder<Object, Object> builder : allEntryTypeMakers()) {
      LocalCache<Object, Object> map = makeLocalCache(builder);
      Object keyOne = new Object();
      Object valueOne = new Object();
      int hashOne = map.hash(keyOne);
      ReferenceEntry<Object, Object> entryOne = map.newEntry(keyOne, hashOne, null);
      ValueReference<Object, Object> valueRefOne = map.newValueReference(entryOne, valueOne, 1);
      assertSame(valueOne, valueRefOne.get());
      entryOne.setValueReference(valueRefOne);
      assertSame(keyOne, entryOne.getKey());
      assertEquals(hashOne, entryOne.getHash());
      assertNull(entryOne.getNext());
      assertSame(valueRefOne, entryOne.getValueReference());
      Object keyTwo = new Object();
      Object valueTwo = new Object();
      int hashTwo = map.hash(keyTwo);
      ReferenceEntry<Object, Object> entryTwo = map.newEntry(keyTwo, hashTwo, entryOne);
      ValueReference<Object, Object> valueRefTwo = map.newValueReference(entryTwo, valueTwo, 1);
      assertSame(valueTwo, valueRefTwo.get());
      entryTwo.setValueReference(valueRefTwo);
      assertSame(keyTwo, entryTwo.getKey());