Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Overlay/Merge an ImmutableMap over another ImmutableMap
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
public class MapTransforms
{
/**
* This assumes that <code>defaults</code> specifies the complete domain of the set of keys/values supported by <code>overlay</code>.
* <p/>
* This is implemented as a <code>View</code> as described in the documentation for {@link com.google.common.collect.Maps#transformEntries(Map, Maps.EntryTransformer)} and does not copy either map and returns the values on demand.
* This means if you want to transform the entire <code>Map</code> to the merged version at once you need to wrap the return value in <code>ImmutableMap.copyOf()</code> which will eagerly
* apply the transformation and process the entire map only once.
* <p/>
* There is no sanity check on this that a given key exists in the <code>defaults.keySet()</code>
*
* @see com.google.common.collect.Maps.EntryTransformer
* @param defaults complete domain to overlay new <code>Map</code> onto
* @param overlay <code>Map</code> contents to replace what is contained in <code>defaults</code>
* @param <K> Key type
* @param <V> Value type
* @return returns a <code>View</code> as an <code>ImmutableMap</code> that returns the values in <code>overlay</code> if they exist otherwise the value in <code>defaults</code>.
*/
public static <K, V> Map<K, V> overlay(@Nonnull final Map<K, V> defaults, @Nonnull final Map<K, V> overlay)
{
return Maps.transformEntries(defaults, new Maps.EntryTransformer<K, V, V>()
{
@Override
public V transformEntry(@Nullable final K key, @Nullable final V value)
{
return overlay.containsKey(key) ? overlay.get(key) : value;
}
});
}
/**
* This does the same thing that {@link #overlay(Map, Map)} does, but wraps the return value in {@link ImmutableMap#copyOf(Map)} to eagerly apply the transform.
*
* @param defaults complete domain to overlay new <code>Map</code> onto
* @param overlay <code>Map</code> contents to replace what is contained in <code>defaults</code>
* @param <K> Key type
* @param <V> Value type
* @return applyes {@link #overlay(Map, Map)} and wraps the result in {@link ImmutableMap#copyOf(Map)}
*/
public static <K,V> Map<K,V> merge(@Nonnull final Map<K,V> defaults, @Nonnull final Map<K,V> overlay)
{
return ImmutableMap.copyOf(overlay(defaults,overlay));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment