@Override
  public @Nullable V remove(Object key) {
    @SuppressWarnings("unchecked")
    K castKey = (K) key;
    @SuppressWarnings({"rawtypes", "unchecked"})
    Node<K, V>[] node = new Node[1];
    @SuppressWarnings("unchecked")
    V[] oldValue = (V[]) new Object[1];
    RemovalCause[] cause = new RemovalCause[1];
    Object lookupKey = nodeFactory.newLookupKey(key);

    data.computeIfPresent(lookupKey, (k, n) -> {
      synchronized (n) {
        requireIsAlive(key, n);
        oldValue[0] = n.getValue();
        if (oldValue[0] == null) {
          cause[0] = RemovalCause.COLLECTED;
        } else if (hasExpired(n, expirationTicker().read())) {
          cause[0] = RemovalCause.EXPIRED;
        } else {
          cause[0] = RemovalCause.EXPLICIT;
        }
        if (cause[0].wasEvicted()) {
          notifyEviction(castKey, oldValue[0], cause[0]);
        }
        discardRefresh(lookupKey);
        node[0] = n;
        n.retire();
      }
      return null;
    });

    if (cause[0] != null) {
      afterWrite(new RemovalTask(node[0]));
      notifyRemoval(castKey, oldValue[0], cause[0]);
    }
    return (cause[0] == RemovalCause.EXPLICIT) ? oldValue[0] : null;
  }
@CheckMaxLogLevel(ERROR)
  @Test(dataProvider = "caches")
  @CacheSpec(population = Population.EMPTY, keys = ReferenceType.STRONG)
  public void brokenEquality_removeConditionally(
      BoundedLocalCache<MutableInt, Int> cache, CacheContext context) {
    testForBrokenEquality(cache, context, key -> {
      boolean removed = cache.remove(key, context.absentValue());
      assertThat(removed).isTrue();
    });
  }