package tc.oc.commons.core.collection; import java.util.Collection; import java.util.Map; import java.util.Optional; import java.util.function.BiPredicate; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Stream; import com.google.common.collect.ForwardingMap; import tc.oc.commons.core.stream.BiStream; public interface MapHelper<K, V> extends Map<K, V> { static <K, V> MapHelper<K, V> wrap(Map<K, V> map) { return new Wrapper<>(map); } default void removeIf(BiPredicate<K, V> filter) { entrySet().removeIf(entry -> filter.test(entry.getKey(), entry.getValue())); } default void retainIf(BiPredicate<K, V> filter) { entrySet().removeIf(entry -> !filter.test(entry.getKey(), entry.getValue())); } default void removeIfValue(Predicate<V> filter) { values().removeIf(filter); } default void putAbsent(Map<K, V> src) { for(Map.Entry<K, V> entry : src.entrySet()) { if(!containsKey(entry.getKey())) { put(entry.getKey(), entry.getValue()); } } } default void putAll(Collection<K> src, V value) { for(K k : src) { put(k, value); } } default Stream<K> keyStream() { return keySet().stream(); } default Stream<V> valueStream() { return values().stream(); } default Stream<Map.Entry<K, V>> entryStream() { return entrySet().stream(); } default BiStream<K, V> stream() { return BiStream.from(this); } default Optional<V> value(K key) { return Optional.ofNullable(get(key)); } default Optional<V> ifPresent(K key, Consumer<V> consumer) { final Optional<V> value = value(key); value.ifPresent(consumer); return value; } /** * Alternative to {@link #computeIfAbsent(Object, Function)} that takes a * {@link Supplier} instead of a {@link Function}. Usually, the caller already has * the key, since they just passed it to this method, and having to declare a * duplicate key variable for the lambda is just annoying. */ default V computeIfAbsent(K key, Supplier<V> computer) { return computeIfAbsent(key, key0 -> computer.get()); } } class Wrapper<K, V> extends ForwardingMap<K, V> implements MapHelper<K, V> { private final Map<K, V> delegate; Wrapper(Map<K, V> delegate) { this.delegate = delegate; } @Override protected Map<K, V> delegate() { return delegate; } }