zoukankan      html  css  js  c++  java
  • Java Maps的9个常见问题

    一般来说,Map是一种由键值对组成的数据结构,其中键(key)在Map中是不能重复的;

    本篇文章总结了9个最常见的问题(关于Java Map及其实现类);

    出于简单考虑,在代码例子中我将不使用泛型,因此,我将仅仅写上Map而不是写上Map<K, V>,且Map中的Key和Value都是可以比较的,意味着K和V都实现了Comparable接口;

    1.Map转List

    在Java中,Map接口提供了三个集合视图,即key set, value set,和key-value set。它们都可以转成List集合,如下代码所示:

    // key list
    List keyList = new ArrayList(map.keySet());
    // value list
    List valueList = new ArrayList(map.valueSet());
    // key-value list
    List entryList = new ArrayList(map.entrySet());

    2.迭代遍历Map中的key-value

    迭代遍历Map中的键值对是最基本的操作。在Java中,键值对信息存储在Map.Entry类中。通过调用Map.entrySet()方法会返回键值对集合,因此最有效的遍历Map中的键值对如下代码所示:

    for(Entry entry: map.entrySet()) {
        // get key
        K key = entry.getKey();
        // get value
        V value = entry.getValue();
    }

    当然,也可以通过迭代器遍历,如下代码:

    while(itr.hasNext()) {
        Entry entry = itr.next();
        // get key
        K key = entry.getKey();
        // get value
        V value = entry.getValue();
    }

    3.Map中的元素按Key排序

    对Map中的元素按key排序是另一个经常使用的操作。有一种方法是将Map中的元素放进List集合,然后通过一个比较器对集合进行排序,如下代码示例:

            List list = new ArrayList(map.entrySet());
            Collections.sort(list, new Comparator() {
                public int compare(Entry e1, Entry e2) {
                    return e1.getKey().compareTo(e2.getKey());
                    }
                });
            }

    另一种方法是使用SortedMap,其提供了对Key进行排序的功能;前提是Map中的Key需要实现Comparable接口或者通过构造方法传入比较器;

    TreeMap是SortedMap的一个实现类,它的构造方法能够接收一个比较器,以下代码展示了如何将普通Map转成SortedMap:

    SortedMap sortedMap = new TreeMap(new Comparator() {
        @Override
        public int compare(K k1, K k2) {
        return k1.compareTo(k2);
        }
    });
    sortedMap.putAll(map);

    4.Map中的元素按Value排序

    同样可以参考前面的将Map的元素放进List集合然后传入比较器进行排序,不过这次要比较的对象是Entry.getValue()。如下代码所示:

    List list = new ArrayList(map.entrySet());
    Collections.sort(list, new Comparator() {
        @Override
        public int compare(Entry e1, Entry e2) {
            return e1.getValue().compareTo(e2.getValue());
        }
    });

    对于这个问题,当map中的value都是唯一的情况,我们仍然可以使用sorted map来排序,在这种情况下,你可以将key赋值给value,value赋值给key来实现该功能;但是这种解决方法十分受限,非常不建议使用;

    5.初始化一个不可修改的Map

    当你想要使用Map来存储一些常量时,将他们存储到一个不可修改的Map是一个好习惯。这种防御性编程技术会帮助你创建一个能安全使用且线程安全的map;

    我们可以使用静态代码块来初始化一个静态不可变的map,如下代码:

    public class Test {
    private static final Map map;
        static {
            map = new HashMap();
            map.put(1, "one");
            map.put(2, "two");
        }
    }

    然而以上代码是有问题的,即使map被声明成static final,我们仍然可以操作该map,如Test.map.put(3,"three");因此,这不是不可变的map;

    为了创建一个不可变的map,我们需要一个额外的map对象,将它作为入参传入Collections.unmodifiableMap方法中,然后得到一个不可变的Map,如下代码:

    public class Test {
    private static final Map map;
    static {
    Map aMap = new HashMap();
    aMap.put(1, "one");
    aMap.put(2, "two");
    map = Collections.unmodifiableMap(aMap);
    }
    }

    此时,当我们运行Test.map.put(3,"three")将抛出UnsupportedOperationException异常;

    Google的Guava库支持多种方式创建不可变的Map,想学习的可以参考其官方使用手册;

    6.HashMap, TreeMap, 和Hashtable的区别

    HashMap, TreeMap, 和Hashtable是Map接口的三个主要实现类,它们之间的主要区别如下:

    • 是否有序。HashMap和HashTable不会保证元素的有序性,随着时间推移,元素的顺序可能会发生改变;然而TreeMap是有序的,会根据自然顺序或依据比较器排序;
    • key- value限制。HashMap允许key和value为null(key只能有一个为null,因为key不能重复)。HashTable不允许key 或value为null;TreeMap如果使用自然顺序或者比较器不允许key为null,使用null key将抛出异常;另外,在TreeMap中value是可以为null的;
    • 是否同步。只有Hashtable是同步的,其它的不是。如果线程安全不在考虑范围的话,强烈建议使用HashTable。

    另一个比较完整的比较如下:

    它们之间的更多比较信息可参考如下链接:

    http://www.programcreek.com/2013/03/hashmap-vs-treemap-vs-hashtable-vs-linkedhashmap/

    7.反向查找Map

    有时候,我们需要key和value都唯一,这种情况允许我们创建一个双向查找Map,也就是说,可以通过唯一的value去查找唯一的Key,遗憾的是,JDK并不支持该数据结构;

    Apache Common Collections 和 Guava 提供了对双向查找Map的支持,被叫做BidiMap和BiMap,它们规定了key和value必须是1对1的关系。

    8.Map浅拷贝

    大部分Map实现类都提供了构造方法,用于对另外一个Map的复制,但是这个复制操作不是同步的,意味着一个线程在对Map进行复制操作的时候,另一个线程可能会对它结构性的修改(增删该等操作);为了阻止意外的非同步操作,应该事先使用Collections.synchronizedMap()方法去创建一个同步Map,如下:

    Map copiedMap = Collections.synchronizedMap(map);

    另外一种浅拷贝方法是使用clone()方法,然而它并不被集合框架作者Josh Bloch推荐;他曾在一次访谈中谈到关于”拷贝构造方法VS克隆方法“,他说:

    I often provide a public clone method on concrete classes because people expect it. ... It’s a shame that Cloneable is broken, but it happens. ... Cloneable is a weak spot, and I think people should be aware of its limitations.

    9.创建一个空Map

    如果是不可变Map,使用Collections工具类创建,如下:

    map = Collections.emptyMap();

    否则,直接new,如下:

    map = new HashMap();

    译文链接:http://www.programcreek.com/2013/09/top-9-questions-for-java-map/

  • 相关阅读:
    [原创]中值滤波算法处理位图(C#实现)
    vue3弹窗可以拖曳、放大、缩小、最大化、最小化插件
    请博客园的高手们帮忙看一个问题 为什么 set datefirst 1 写到存储过程中就不起作用了.
    Sql server学习笔记 set 注意事项
    Sql server 学习笔记全局变量
    使用C# 发送Email 邮件方法
    给安装Visual Studio 2010遇到的一些问题建议
    IIS建立网站后显示“403.1禁止访问”的解决方法
    Window xp 换成Windows 7 C盘内留有老的windows 版本提示
    COUNT() 和Count(字段) 区别
  • 原文地址:https://www.cnblogs.com/chenpi/p/5488903.html
Copyright © 2011-2022 走看看