google的guava项目提对Map供了丰富强大的转换功能(参见guava jar包中的com.google.common.collect.Maps )
Maps.transform系列方法可以对Map的Value类型进行转换,
比如:
public static <K, V1, V2> Map<K, V2> transformEntries( Map<K, V1> fromMap,EntryTransformer<? super K, ? super V1, V2> transformer)
可以将一个Map<K,V1>
转为一个Map<K,V2>
对象。
但是guava中并没有提供对Key的类型转换。为什么呢?
对Map提供Key类型转换不一定是安全的,是有风险的。比如用ByteBuffer->byte[],我们知道 byte[]
做Key是有问题的(因为两个内容相同的byte[]
计算出的hashcode不同,所以在一般的设计中不会用byte[]
做为key)。
虽然实现Key类型转换并不复杂,但guava中并没有将它做为通用方法提供,以防止错误使用。对于java.util.Set也没有提供transform方法,道理是一样的。
但是在现实设计中有的时候真的需要一个Key类型的转换,就需要自己来实现它,于是我参照guava中transform的设计,自己实现了java.util.Map
和java.util.Set
的Key类型转换方法(不依赖guava)。
如下图,
其实核心的方法就是两个静态方法,如上图红框标的,一个用于转换Map<K1,V>
到Map<K2,V>
,另一个用来转换Set<E1>
到Set<E2>
TransformedMap<K1, K2, V>
,TransformedSet<E1, E2>
两个内部类就是对应上面两个方法的实现部分.
Set和Map的转换核心是Iterator的转换,所以从guava中抄了TransformedIterator<F, T>
的代码实现。
完整实现代码如下:
CollectionUtils.java
package net.gdface.facelog.client;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class CollectionUtils {
private CollectionUtils() {}
public static interface Function<F, T> {
T apply( F input);
}
/**
* dual transform type between L and R<br>
* {@link #toRight(Object)} L -> R<br>
* {@link #fromRight(Object)} R -> L
* @author guyadong
*
* @param <L> left type
* @param <R> right type
*/
public static interface DualTransformer<L,R>{
R toRight(L input);
L fromRight(R input);
}
public static final <L,R> DualTransformer<L,R> asDualTransformer(final Function<L,R> t1,final Function<R,L>t2){
checkNotNull(t1);
checkNotNull(t2);
return new DualTransformer<L,R>(){
@Override
public R toRight(L input) {
return t1.apply(input);
}
@Override
public L fromRight(R input) {
return t2.apply(input);
}
};
}
public static final <L,R> Function<L,R> asToRightTransformer(final DualTransformer<L,R> dual){
checkNotNull(dual);
return new Function<L,R>(){
@Override
public R apply(L input) {
return dual.toRight(input);
}
};
}
public static final <L,R> Function<R,L> asFromRightTransformer(final DualTransformer<L,R> dual){
checkNotNull(dual);
return new Function<R,L>(){
@Override
public L apply(R input) {
return dual.fromRight(input);
}
};
}
private static boolean equal( Object a, Object b) {
return a == b || (a != null && a.equals(b));
}
static <T> T checkNotNull(T reference) {
if (reference == null) {
throw new NullPointerException();
}
return reference;
}
static <V> V safeGet(Map<?, V> map, Object key) {
checkNotNull(map);
try {
return map.get(key);
} catch (ClassCastException e) {
return null;
} catch (NullPointerException e) {
return null;
}
}
/** @see #tranformKeys(Map, DualTransformer)*/
public static final<K1,K2,V>Map<K2,V> tranformKeys(Map<K1,V>fromMap,
Function<K1, K2> transformer2,
Function<K2, K1> transformer1){
return tranformKeys(fromMap,asDualTransformer(transformer2,transformer1));
}
/**
* Returns a view of a map where each value is transformed by a function. All
* other properties of the map, such as iteration order, are left intact. <br>
* see also {@link com.google.common.collect.Maps#transformEntries(Map, com.google.common.collect.Maps.EntryTransformer)}
* @param fromMap
* @param transformer
* @return
*/
public static final<K1,K2,V>Map<K2,V> tranformKeys(Map<K1,V>fromMap,
DualTransformer<K1, K2> transformer){
return new TransformedMap<K1, K2, V>(fromMap,transformer);
}
/** @see #transform(Set, DualTransformer)*/
public static final <E1,E2>Set<E2>transform(Set<E1> fromSet,
Function<E1, E2> transformer2,
Function<E2, E1> transformer1){
return transform(fromSet,asDualTransformer(transformer2,transformer1));
}
/**
* Returns a view of a set where each key is transformed by a function. All
* other properties of the map, such as iteration order, are left intact. <br>
* see also {@link com.google.common.collect.Maps#transformEntries(Map, com.google.common.collect.Maps.EntryTransformer)}
* @param fromSet
* @param transformer
* @return
*/
public static final <E1,E2>Set<E2>transform(Set<E1> fromSet,
DualTransformer<E1,E2> transformer){
return new TransformedSet<E1,E2>(fromSet,transformer);
}
/**
* Returns an iterator that applies {@code function} to each element of {@code fromIterator}.<br>
* see also {@link com.google.common.collect.Iterators#transform(Iterator, com.google.common.base.Function)}
* @param fromIterator
* @param transformer
* @return
*/
public static <F, T> Iterator<T> transform(final Iterator<F> fromIterator,
final Function<? super F, ? extends T> transformer) {
return new TransformedIterator<F, T>(fromIterator,transformer);
}
static class TransformedIterator<F, T> implements Iterator<T> {
final Iterator<? extends F> backingIterator;
private Function<? super F, ? extends T> transformer;
TransformedIterator(Iterator<? extends F> backingIterator,Function<? super F, ? extends T> transformer) {
this.backingIterator = checkNotNull(backingIterator);
this.transformer = checkNotNull(transformer);
}
@Override
public final boolean hasNext() {
return backingIterator.hasNext();
}
@Override
public final T next() {
return transformer.apply(backingIterator.next());
}
@Override
public final void remove() {
backingIterator.remove();
}
}
static class TransformedSet<E1, E2> extends AbstractSet<E2> {
final Set<E1> fromSet;
private final DualTransformer<E1, E2> transformer;
TransformedSet(Set<E1> fromSet, DualTransformer<E1, E2> transformer) {
checkNotNull(fromSet);
checkNotNull(transformer);
this.fromSet = fromSet;
this.transformer = transformer;
}
@Override
public int size() {
return fromSet.size();
}
@Override
public Iterator<E2> iterator() {
return transform(fromSet.iterator(), asToRightTransformer(transformer));
}
@Override
public boolean add(E2 e) {
return fromSet.add(transformer.fromRight(e));
}
@SuppressWarnings("unchecked")
@Override
public boolean contains(Object o) {
try {
return fromSet.contains(transformer.fromRight((E2) o));
} catch (ClassCastException e) {
return false;
}
}
@SuppressWarnings("unchecked")
@Override
public boolean remove(Object o) {
try {
return fromSet.remove(transformer.fromRight((E2) o));
} catch (ClassCastException e) {
return false;
}
}
}
static class TransformedMap<K1, K2, V> extends AbstractMap<K2, V> {
final Map<K1, V> fromMap;
private DualTransformer<K1,K2> transformer;
TransformedMap(Map<K1, V> fromMap, DualTransformer<K1,K2> transformer) {
checkNotNull(fromMap);
checkNotNull(transformer);
this.fromMap = fromMap;
this.transformer = transformer;
}
@SuppressWarnings("unchecked")
@Override
public V get(Object key) {
try {
return fromMap.get(transformer.fromRight((K2) key));
} catch (ClassCastException e) {
return null;
}
}
@SuppressWarnings("unchecked")
@Override
public boolean containsKey(Object key) {
try {
return fromMap.containsKey(transformer.fromRight((K2) key));
} catch (ClassCastException e) {
return false;
}
}
@Override
public V put(K2 key, V value) {
return fromMap.put(transformer.fromRight(key), value);
}
@SuppressWarnings("unchecked")
@Override
public V remove(Object key) {
try {
return fromMap.remove(transformer.fromRight((K2) key));
} catch (ClassCastException e) {
return null;
}
}
@Override
public Set<Entry<K2, V>> entrySet() {
return new EntrySet<K2,V>(){
@Override
Map<K2, V> map() {
return TransformedMap.this;
}
@Override
public Iterator<java.util.Map.Entry<K2, V>> iterator() {
return transform(fromMap.entrySet().iterator(),
new Function<Entry<K1,V>,Entry<K2,V>>(){
@Override
public java.util.Map.Entry<K2, V> apply(java.util.Map.Entry<K1, V> input) {
return new TransformedEntry<K1,K2,V>(input,asToRightTransformer(TransformedMap.this.transformer));
}});
}};
}
abstract static class EntrySet<K, V> extends AbstractSet<Entry<K, V>> {
abstract Map<K, V> map();
@Override
public int size() {
return map().size();
}
@Override
public boolean contains(Object o) {
if (o instanceof Entry) {
Entry<?, ?> entry = (Entry<?, ?>) o;
Object key = entry.getKey();
V value = safeGet(map(), key);
return equal(value, entry.getValue())
&& (value != null || map().containsKey(entry.getKey()));
}
return false;
}
@Override
public boolean remove(Object o) {
if (contains(o)) {
Entry<?, ?> entry = (Entry<?, ?>) o;
return map().keySet().remove(entry.getKey());
}
return false;
}
}
static class TransformedEntry<K1,K2,V> implements Entry<K2, V> {
final Entry<K1,V>fromEntry;
final Function<K1, K2> transformer2;
TransformedEntry(Entry<K1,V>fromEntry,Function<K1, K2> transformer2){
checkNotNull(fromEntry);
this.fromEntry = fromEntry;
checkNotNull(transformer2);
this.transformer2 = transformer2;
}
@Override
public K2 getKey() {
return transformer2.apply(fromEntry.getKey());
}
@Override
public V getValue() {
return fromEntry.getValue();
}
@Override
public V setValue(V value) {
return fromEntry.setValue(value);
}
@Override
public boolean equals(Object object) {
if(object instanceof TransformedEntry){
return fromEntry.equals((TransformedEntry<?, ?, ?>)object);
}
return super.equals(object);
}
@Override
public int hashCode() {
return fromEntry.hashCode();
}
@Override
public String toString() {
return fromEntry.toString();
}
}
}
}
注意:
transfrom方法返回的新对象是原对象的代理对象,对新对象的任何操作实际都是原对象的操作