关于Java中的Map相关的使用

来源:互联网 发布:金字塔软件下载 编辑:程序博客网 时间:2024/06/06 02:42

上班快两个月,Java很多地方还不算特别清晰,但是遇到了几个关于Map的地方,简单总结一下。

1、为什么要使用Map<Integer,String> m = new HashMap<Integer, String>();这种方式而不是HashMap<Integer,String> m = new HashMap<Integer, String>();

       一直看公司里的其他人是这么写的,于是自己也这么写,但是从来没有想过为什么要这么写。后来偶然逛论坛时发现有人提这个问题,但是自己从来没有想过这个问题,实在羞愧。。。。

        其实这么写的目的是为了保证代码的可扩展性,可扩展性这个东西说起来似乎很虚,但是工作之后的确会发现需求是在不断发生变化的,因此代码良好的可扩展性对于代码而言实际上是一种必然的要求。

       这么写的目的实际上是OO设计中的“面向接口编程”的完美体现。Map是一个接口,而HashMap是一个类,这种方式能够保证在需求发生变化时,可以换成其他的Map,如TreeMap、ConcurrenMap等,这样就可以修改比较少的代码来换取新功能的实现。

       这种思想在设计模式“策略模式”中有比较好的体现。可以参见《Head First Pattern》的第一章。

2、HashMap的遍历方式

      HashMap应该是工作中使用的比较频繁的一个类,而这个类的遍历方式有两种。

      2.1 通过遍历HashMap的keySet来进行遍历

Map<Integer,String> m = new HashMap<Integer, String>();m.put(1, "a");m.put(2, "b");m.put(3, "c");for(Integer i : m.keySet()){System.out.println(m.get(i));}

    可以看看keySet()方法的源码,在AbstractMap中具体实现

    public Set<K> keySet() {if (keySet == null) {    keySet = new AbstractSet<K>() {public Iterator<K> iterator() {    return new Iterator<K>() {private Iterator<Entry<K,V>> i = entrySet().iterator();public boolean hasNext() {    return i.hasNext();}public K next() {    return i.next().getKey();}public void remove() {    i.remove();}                    };}public int size() {    return AbstractMap.this.size();}public boolean contains(Object k) {    return AbstractMap.this.containsKey(k);}    };}return keySet;    }

      这里实际上是调用了HashMap的entrySet()方法返回一个Set<Map.Entry<K,V>>然后调用这个set的iterator()方法来进行遍历。

   2.2 使用HashMap的entrySet来进行遍历

Map<Integer,String> m = new HashMap<Integer, String>();m.put(1, "a");m.put(2, "b");m.put(3, "c");for(Map.Entry<Integer, String> me : m.entrySet()){System.out.println(me.getKey()+" "+me.getValue());}

         这种方式是调用HashMap的entrySet方法,这个方法和第一种方法一样返回一个Set<Map.Entry<K,V>>,但是HashMap中的所有数据都直接存储在这个Entry里了。
    2.3 这两种方法的效率对比

        当只需要将HashMap中的key值取出来的时候,显然直接使用keySet()方法会效率高;而当在遍历的过程中需要去除value值就会使得第二种方法的效率大大降低,因为这相当于遍历HashMap两次。因为在用get()方法时会多次调用equals()方法和hasCode()方法。

3、HashMap在遍历过程中删除元素

      使用Map.Entry进行删除元素:

Map<Integer,String> m = new HashMap<Integer, String>();m.put(1, "a");m.put(2, "b");m.put(3, "c");for(Map.Entry<Integer, String> me : m.entrySet()){if(me.getKey() == 2)m.remove(me.getKey());}

    运行结果:

Exception in thread "main" java.util.ConcurrentModificationExceptionat java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)at java.util.HashMap$EntryIterator.next(HashMap.java:834)at java.util.HashMap$EntryIterator.next(HashMap.java:832)at com.wxg.testMap.main(testMap.java:13)

    使用keySet()来删除元素:

Map<Integer,String> m = new HashMap<Integer, String>();m.put(1, "a");m.put(2, "b");m.put(3, "c");for(Integer i : m.keySet()){if(i == 2)m.remove(i);}
    运行结果:

Exception in thread "main" java.util.ConcurrentModificationExceptionat java.util.HashMap$HashIterator.nextEntry(HashMap.java:793)at java.util.HashMap$KeyIterator.next(HashMap.java:828)at com.wxg.testMap.main(testMap.java:13)

    使用Iterator来删除元素:

Map<Integer,String> m = new HashMap<Integer, String>();m.put(1, "a");m.put(2, "b");m.put(3, "c");Iterator<Map.Entry<Integer, String>> i = m.entrySet().iterator();while(i.hasNext()){Map.Entry<Integer, String> entry = i.next();if(entry.getKey() == 2)i.remove();System.out.println(m.get(2));}


     运行结果:

bnullnull

   在前两种方法中都抛出了ConCurrentModificationException的异常,这种异常出现的结果就是在remove的时候调用HashMap的removeEntryForKey的时候需要判断modCount和expectedModeCount是否相等,不相等的话就会抛出这个异常。

   而在Iterator的remove方法中对这两个变量做了同步,所以不会抛出这个异常。




0 0
原创粉丝点击