ConcurrentHashMultimap implements Multimap<K, V> { @Override public boolean put(@Nullable K key, @Nullable V value) { Preconditions.checkNotNull(key); Preconditions.checkNotNull(value); return putWithConflictResolution(key, value, defaultConflictResolver); } ConcurrentHashMultimap(ValueIdentityExtractor<V> valueIdentityExtractor, ConflictResolver<V> conflictResolver); @Override boolean put(@Nullable K key, @Nullable V value); @Override boolean remove(@Nullable Object key, @Nullable Object value); boolean removeIf(K key, V value, Predicate<V> match); @Override boolean putAll(@Nullable K key, Iterable<? extends V> values); @Override boolean putAll(Multimap<? extends K, ? extends V> values); @Override Collection<V> replaceValues(@Nullable K key, Iterable<? extends V> values); @Override Collection<V> removeAll(@Nullable Object key); @Override void clear(); @Override Collection<V> get(@Nullable K key); @Override Set<K> keySet(); @Override Multiset<K> keys(); @Override Collection<V> values(); @Override Collection<Map.Entry<K, V>> entries(); @Override int size(); @Override boolean isEmpty(); @Override boolean containsKey(@Nullable Object key); @Override boolean containsValue(@Nullable Object value); @Override boolean containsEntry(@Nullable Object key, @Nullable Object value); @Override Map<K, Collection<V>> asMap();  }
@Test public void customizableConflictResolution() throws Exception { final ConcurrentHashMultimap.ConflictResolver<TestEntity> onlyReplaceV1 = (old, replacement) -> old.value.contains("v1"); ConcurrentHashMultimap<String, TestEntity> multiMapThatOnlyReplacesV1 = new ConcurrentHashMultimap<>(TestEntity.idExtractor, onlyReplaceV1); multiMapThatOnlyReplacesV1.put("first", new TestEntity("1", "v1")); assertThat(multiMapThatOnlyReplacesV1.put("first", new TestEntity("1", "v2"))).isTrue(); assertThat(multiMapThatOnlyReplacesV1.put("first", new TestEntity("1", "v1"))).isFalse(); }