zoukankan      html  css  js  c++  java
  • Map之一个Key存多个Value的MultiValueMap(一个键多个值)

     

      在日常的开发中经常用到键值对,也就是Map啦,我们知道Map是一个接口,它的特点是一个Key对应一个Value,也就是一个键对应一个值,但是往往我们需要一个Key对应多个Value,这种时候系统的API就无法满足我们的需要了,因此今天介绍一个我封装的一个Key对应多个Value,既一个键对应多个值的MultiValueMap。 
      第二个,我们的MultiValueMap要想什么Key-Value都可以放,就要用到泛型,泛型不好的同学也不用担心,只要你用过MapHashMap我保准你看得懂。

    MultiValueMap接口的定义

      用过Map的人都知道,Map是一个接口(interface),所以我们这里也把MultiValueMap定义成一个接口。那么需要那些方法呢,我们来列个表:

    • 添加一个Key对应一个Value的:void add(K, V);
    • 添加一个Key对应多个Value的:void add(K, List);
    • 设置一个Key对应一个Value的:void set(K, V);
    • 设置一个Key对应多个Value的:void set(K, List);
    • 移除一个Key和它对应的Value:List remove(K);
    • 清除所有Value的:void clear();
    • 拿到所有Key的集合:Set keySet();
    • 拿到所有的值:List values();
    • 拿到一个Key对应的某个值:V getValue(K, index);
    • 拿到一个Key对应的所有Value:List getValues(K);
    • 拿到MultiValueMap的大小:int size();
    • 判断是否为空MultiValueMap:boolean isEmpty();
    • 判断是否包含某个Key:boolean containKey(K);

      下面我们根据分析先把MultiValueMap接口定义出来,其实这个封装是我的开源项目NoHttp中提出来的,有兴趣的看官光顾下NoHttp,废话不多说,上代码:

    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * <p>Can save multiple the value of the map.</p>
     * Created in Jan 10, 2016 5:00:07 PM.
     *
     * @author Yan Zhenjie;
     */
    public interface MultiValueMap<K, V> {
    
        /**
         * 添加Key-Value。
         *
         * @param key   key.
         * @param value value.
         */
        void add(K key, V value);
    
        /**
         * 添加Key-List<Value>。
         *
         * @param key    key.
         * @param values values.
         */
        void add(K key, List<V> values);
    
        /**
         * 设置一个Key-Value,如果这个Key存在就被替换,不存在则被添加。
         *
         * @param key   key.
         * @param value values.
         */
        void set(K key, V value);
    
        /**
         * 设置Key-List<Value>,如果这个Key存在就被替换,不存在则被添加。
         * @param key    key.
         * @param values values.
         * @see #set(Object, Object)
         */
        void set(K key, List<V> values);
    
        /**
         * 替换所有的Key-List<Value>。
         *
         * @param values values.
         */
        void set(Map<K, List<V>> values);
    
        /**
         * 移除某一个Key,对应的所有值也将被移除。
         *
         * @param key key.
         * @return value.
         */
        List<V> remove(K key);
    
        /**
         * 移除所有的值。
         * Remove all key-value.
         */
        void clear();
    
        /**
         * 拿到Key的集合。
         * @return Set.
         */
        Set<K> keySet();
    
        /**
         * 拿到所有的值的集合。
         *
         * @return List.
         */
        List<V> values();
    
        /**
         * 拿到某一个Key下的某一个值。
         *
         * @param key   key.
         * @param index index value.
         * @return The value.
         */
        V getValue(K key, int index);
    
        /**
         * 拿到某一个Key的所有值。
         *
         * @param key key.
         * @return values.
         */
        List<V> getValues(K key);
    
        /**
         * 拿到MultiValueMap的大小.
         *
         * @return size.
         */
        int size();
    
        /**
         * 判断MultiValueMap是否为null.
         *
         * @return True: empty, false: not empty.
         */
        boolean isEmpty();
    
        /**
         * 判断MultiValueMap是否包含某个Key.
         *
         * @param key key.
         * @return True: contain, false: none.
         */
        boolean containsKey(K key);
    
    }

      是不是有些小激动呢,接口终于撸完了。是不是就可以用了呢,答案当然是不能,我们知道Map使用的时候假如是用HashMap是这样实例化的:Map<K, V> map = new HashMap<>();,那么我们的MultiValueMap是不是也要提供一个像HashMap一个样实现类呢?

    MultiValueMap接口的实现类LinkedMultiValueMap

    1. 实现MultiValueMap接口要implements MultiValueMap...
    2. 既然是可以容纳任何类型的MultiValueMap,实现类LinkedMultiValueMap也要用泛型

        分析到里我们先把类的雏形写出来:

    public class LinkedMultiValueMap<K, V> implements MultiValueMap<K, V> {
        ...
    }
    • 1
    • 2
    • 3

      看到这里有经验的小伙伴就会发现这尼玛和MapHashMap一个原理啊,这就对了,当我们看到LinkedMultiValueMap的时候就应该知道我们会用到LinkedHashMap。 
      这里把存放数据的原理分析一下,一个Key对应多个Value,我第一个想到的样子是:Map<K, List<Value>>,综上所述我们的数据源就出来了:

    public class LinkedMultiValueMap<K, V> implements MultiValueMap<K, V> {
        protected Map<K, List<V>> mSource = new LinkedHashMap<K, List<V>>();
        ...
    }
    • 1
    • 2
    • 3
    • 4

      接下来我们就该实现MultiValueMap接口所有的方法啦,嗯没啥好说的了,上代码,不懂的地方有注释:

    import java.util.ArrayList;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * Created in Jan 10, 2016 5:03:17 PM.
     *
     * @author Yan Zhenjie;
     */
    public class LinkedMultiValueMap<K, V> implements MultiValueMap<K, V> {
    
        protected Map<K, List<V>> mSource = new LinkedHashMap<K, List<V>>();
    
        public LinkedMultiValueMap() {
        }
    
        @Override
        public void add(K key, V value) {
            if (key != null) {
                // 如果有这个Key就继续添加Value,没有就创建一个List并添加Value
                if (!mSource.containsKey(key))
                    mSource.put(key, new ArrayList<V>(2));
                mSource.get(key).add(value);
            }
        }
    
        @Override
        public void add(K key, List<V> values) {
            // 便利添加进来的List的Value,调用上面的add(K, V)方法添加
            for (V value : values) {
                add(key, value);
            }
        }
    
        @Override
        public void set(K key, V value) {
            // 移除这个Key,添加新的Key-Value
            mSource.remove(key);
            add(key, value);
        }
    
        @Override
        public void set(K key, List<V> values) {
            // 移除Key,添加List<V>
            mSource.remove(key);
            add(key, values);
        }
    
        @Override
        public void set(Map<K, List<V>> map) {
            // 移除所有值,便利Map里的所有值添加进来
            mSource.clear();
            mSource.putAll(map);
        }
    
        @Override
        public List<V> remove(K key) {
            return mSource.remove(key);
        }
    
        @Override
        public void clear() {
            mSource.clear();
        }
    
        @Override
        public Set<K> keySet() {
            return mSource.keySet();
        }
    
        @Override
        public List<V> values() {
            // 创建一个临时List保存所有的Value
            List<V> allValues = new ArrayList<V>();
    
            // 便利所有的Key的Value添加到临时List
            Set<K> keySet = mSource.keySet();
            for (K key : keySet) {
                allValues.addAll(mSource.get(key));
            }
            return allValues;
        }
    
        @Override
        public List<V> getValues(K key) {
            return mSource.get(key);
        }
    
        @Override
        public V getValue(K key, int index) {
            List<V> values = mSource.get(key);
            if (values != null && index < values.size())
                return values.get(index);
            return null;
        }
    
        @Override
        public int size() {
            return mSource.size();
        }
    
        @Override
        public boolean isEmpty() {
            return mSource.isEmpty();
        }
    
        @Override
        public boolean containsKey(K key) {
            return mSource.containsKey(key);
        }
    
    }

      到这里,实现类也就完了,高手们已经肯定会用了。

    MultiValueMap接口和实现类LinkedMultiValueMap的用法

      其实本来不想写用法的,但是我们还是要本着一个负责人的态度是吧。其实这个封装在开源框架NoHttp中用的很多,很成熟了,下面也再写点用法:

    public static void main(String[] args) {
        MultiValueMap<String, String> stringMultiValueMap = new LinkedMultiValueMap<>();
        // 添加Key为name的
        stringMultiValueMap.add("name", "yolanda");
        stringMultiValueMap.add("name", "yanzhenjie");
        stringMultiValueMap.add("name", "严振杰");
        stringMultiValueMap.add("name", "尤兰达");
        // 添加Key为domain的
        stringMultiValueMap.add("domain", "http://www.yanzhenjie.com");
        stringMultiValueMap.add("domain", "http://www.nohttp.net");
    
        // 拿到某个key的某个值
        System.out.println("name的第三个值:" + stringMultiValueMap.getValue("name", 3));
    
        // 打印所有值
        Set<String> keySet = stringMultiValueMap.keySet();
        for (String key : keySet) {
            List<String> values = stringMultiValueMap.getValues(key);
            for (String value : values) {
                System.out.println(key + ": " + value);
            }
        }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

      我们run一下看结果:

    name的第三个值:尤兰达
    name: yolanda
    name: yanzhenjie
    name: 严振杰
    name: 尤兰达
    domain: http://www.yanzhenjie.com
    domain: http://www.nohttp.net

      果然没有问题呀,我得意的笑呀哈哈哈…… 
      还是有疑问的同学在下面留言噢,天很晚了,睡觉。


    欢迎大家关注Android开源网络框架NoHttp:https://github.com/yanzhenjie/NoHttp 
    在线直播视频和代码下载:http://pan.baidu.com/s/1miEOtwG 

  • 相关阅读:
    POJ 3259 Wormholes【BellmanFord】
    POJ 2960 SNim【SG函数的应用】
    ZOJ 3578 Matrixdp水题
    HDU 2897 邂逅明下【bash博弈】
    BellmanFord 算法及其优化【转】
    【转】几个Java的网络爬虫
    thinkphp 反字符 去标签 自动加点 去换行 截取字符串 冰糖
    php 二维数组转 json文本 (jquery datagrid 数据格式) 冰糖
    PHP 汉字转拼音(首拼音,所有拼音) 冰糖
    设为首页与加入收藏 兼容firefox 冰糖
  • 原文地址:https://www.cnblogs.com/jiadp/p/9335437.html
Copyright © 2011-2022 走看看