
org.tenidwa.collections.utils.ContentMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of collections-utils Show documentation
Show all versions of collections-utils Show documentation
Collection utilities for Java 8
The newest version!
package org.tenidwa.collections.utils;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
/**
* Map that uses function of K as keys instead of K.
*
* Its purpose is to allow mapping from keys that don't support
* {@link Object#equals(Object)}. When using the usual {@link Map} that has an
* interface as a key type, there is no sane way to treat instances of
* different types as equal, because then we'd have to:
*
* - re-implement {@link Object#equals(Object)} in every type (which would
* be a lot of duplicated code);
* - or extend every implementation of the interface with an abstract
* class that implements {@link Object#equals(Object)} using methods of that
* interface (which would still be duplicating code, not per interface
* implementation but per interface).
*
*
* "Content" in "ContentMap" means "something equatable that is obtained with
* public methods of interface {@code K}"
*
* For example, if {@code PersonWithoutEquals} and {@code PersonFromStream}
* don't implement equals but have method {@code Person#name()} that returns
* {@link String}, we could map {@code Person}s to something else like this:
*
* Map map =
* new ContentMap(Person::name);
* map.put(new PersonWithoutEquals("Jeff"), 1);
* map.get(new PersonFromStream(streamWithNameJeff)); // 1
*
*
* This map has deterministic ordering.
*
* This map doesn't support methods {@link Map#keySet()} and
* {@link Map#entrySet()} because it doesn't store the keys of type
* {@code K}, it just uses those to obtain the "hidden" keys of type {@code C}.
*
* This map is immutable, mutator methods will throw
* {@link UnsupportedOperationException}.
* @param Key type
* @param Some content obtainable from K
* @param Value type
* @author Georgy Vlasov ([email protected])
* @version $Id$
* @since 0.6.0
*/
public final class ContentMap implements Map {
/**
* Map from content of the base map to its values.
*/
private final transient ImmutableMap map;
/**
* Function to extract content from keys.
*/
private final transient Function function;
/**
* Original map.
*/
private final transient Map original;
/**
* Ctor.
* @param base Base map.
* @param function Function to get content of a key.
*/
public ContentMap(
final ImmutableMap base,
final Function function
) {
this.function = function;
this.map = this.mapContentToValues(base);
this.original = base;
}
@Override
public int size() {
return this.map.size();
}
@Override
public boolean isEmpty() {
return this.map.isEmpty();
}
@Override
public boolean containsKey(Object o) {
return this.map.containsKey(this.key(o));
}
@Override
public boolean containsValue(Object o) {
return this.map.containsValue(o);
}
@Override
public V get(Object o) {
return this.map.get(this.key(o));
}
@Deprecated
@Override
public V put(K k, V v) {
throw new UnsupportedOperationException(
"Put operation is not supported"
);
}
@Deprecated
@Override
public V remove(Object o) {
throw new UnsupportedOperationException(
"Remove operation is not supported"
);
}
@Deprecated
@Override
public void putAll(Map extends K, ? extends V> map) {
throw new UnsupportedOperationException(
"Put all operation is not supported"
);
}
@Deprecated
@Override
public void clear() {
throw new UnsupportedOperationException(
"Clear operation is not supported"
);
}
@Override
public Set keySet() {
return ImmutableSet.copyOf(this.original.keySet());
}
@Override
public Collection values() {
return this.map.values();
}
@Override
public Set> entrySet() {
return ImmutableSet.copyOf(this.original.entrySet());
}
@SuppressWarnings("unchecked")
private C key(Object o) {
return this.function.apply((K)o);
}
/**
* Maps the content of the base map to its values.
* @param base Base map
* @return Map from content of the base map to its values.
*/
private ImmutableMap mapContentToValues(
final ImmutableMap base
) {
final ImmutableMap.Builder builder = ImmutableMap.builder();
for (final Entry entry : base.entrySet()) {
builder.put(
this.key(entry.getKey()),
entry.getValue()
);
}
return builder.build();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy