code: V remap(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
      // ensures that the removal notification is processed after the removal has completed
      @SuppressWarnings({"unchecked", "rawtypes"})
      V[] oldValue = (V[]) new Object[1];
      RemovalCause[] cause = new RemovalCause[1];
      V nv = data.compute(key, (K k, V value) -> {
        V newValue = remappingFunction.apply(k, value);
        if ((value == null) && (newValue == null)) {
          return null;
        }
  
        cause[0] = (newValue == null) ? RemovalCause.EXPLICIT : RemovalCause.REPLACED;
        if (hasRemovalListener() && (value != null) && (newValue != value)) {
          oldValue[0] = value;
        }
  
        return newValue;
      });
      if (oldValue[0] != null) {
        notifyRemoval(key, oldValue[0], cause[0]);
      }
      return nv;
    }
docs: A {@link Map#compute(Object, BiFunction)} that does not directly record any cache statistics.
  
  @param key key with which the specified value is to be associated
  @param remappingFunction the function to compute a value
  @return the new value associated with the specified key, or null if none