java:java.util.Map和java.util.Set的Key类型转换

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.Mapjava.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方法返回的新对象是原对象的代理对象,对新对象的任何操作实际都是原对象的操作

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Java 2集合框架图  集合接口:6个接口(短虚线表示),表示不同集合类型,是集合框架的基础。  抽象类:5个抽象类(长虚线表示),对集合接口的部分实现。可扩展为自定义集合类。  实现类:8个实现类(实线表示),对接口的具体实现。  在很大程度上,一旦您理解了接口,您就理解了框架。虽然您总要创建接口特定的实现,但访问实际集合的方法应该限制在接口方法的使用上;因此,允许您更改基本的数据结构而不必改变其它代码。  · Collection 接口是一组允许重复的对象。  · Set 接口继承 Collection,但不允许重复,使用自己内部的一个排列机制。  · List 接口继承 Collection,允许重复,以元素安插的次序来放置元素,不会重新排列。  · Map接口是一组成对的键-值对象,即所持有的是key-value pairs。Map中不能有重复的key。拥有自己的内部排列机制。  · 容器中的元素类型都为Object。从容器取得元素时,必须把它转换成原来的类型。  Java 2简化集合框架图  集合接口  1.Collection 接口  用于表示任何对象或元素组。想要尽可能以常规方式处理一组元素时,就使用这一接口。  (1) 单元素添加、删除操作:   boolean add(Object o):将对象添加给集合   boolean remove(Object o): 如果集合中有与o相匹配的对象,则删除对象o  (2) 查询操作:   int size() :返回当前集合中元素的数量   boolean isEmpty() :判断集合中是否有任何元素   boolean contains(Object o) :查找集合中是否含有对象o

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值