Java中的Map總結

1.Map用法

類型介紹

Java 自帶了各種 Map 類。這些 Map 類可歸為三種類型:

1. 通用Map,用于在應用程序中管理映射丰辣,通常在 java.util 程序包中實現(xiàn)

HashMap节槐、Hashtable、Properties优幸、LinkedHashMap灾前、IdentityHashMap趴拧、TreeMap胯盯、WeakHashMap懈费、ConcurrentHashMap

2. 專用Map,通常我們不必親自創(chuàng)建此類Map博脑,而是通過某些其他類對其進行訪問

java.util.jar.Attributes憎乙、javax.print.attribute.standard.PrinterStateReasons、java.security.Provider叉趣、java.awt.RenderingHints泞边、javax.swing.UIDefaults

  1. 一個用于幫助我們實現(xiàn)自己的Map類的抽象類

AbstractMap

類型區(qū)別

HashMap
最常用的Map,它根據(jù)鍵的HashCode 值存儲數(shù)據(jù),根據(jù)鍵可以直接獲取它的值,具有很快的訪問速度疗杉。HashMap最多只允許一條記錄的鍵為Null(多條會覆蓋);允許多條記錄的值為 Null繁堡。非同步的。

TreeMap
能夠把它保存的記錄根據(jù)鍵(key)排序,默認是按升序排序乡数,也可以指定排序的比較器,當用Iterator 遍歷TreeMap時闻牡,得到的記錄是排過序的净赴。TreeMap不允許key的值為null。非同步的罩润。

Hashtable
與 HashMap類似,不同的是:key和value的值均不允許為null;它支持線程的同步玖翅,即任一時刻只有一個線程能寫Hashtable,因此也導致了Hashtale在寫入時會比較慢。

LinkedHashMap
保存了記錄的插入順序割以,在用Iterator遍歷LinkedHashMap時金度,先得到的記錄肯定是先插入的.在遍歷的時候會比HashMap慢。key和value均允許為空严沥,非同步的猜极。

Map 初始化

Map<String, String> map = new HashMap<String, String>();

插入元素

map.put("key1", "value1");

獲取元素

map.get("key1")

移除元素

map.remove("key1");

清空map

map.clear();

2.四種常用Map插入與讀取性能比較

測試環(huán)境

jdk1.7.0_80

測試結果

插入10次平均(ms) 讀取10次平均(ms) 插入10次平均(ms) 讀取10次平均(ms) 插入10次平均(ms) 讀取10次平均(ms)
1W 10W 100W 1W 10W 100W
HashMap 56 261 3030 2 21 220
LinkedHashMap 25 229 3069 2 20 216
TreeMap 29 295 4117 5 103 1446
Hashtable 24 234 3275 2 22 259

測試代碼

public class Test {
    // HashMap寫入時間
    static int hashMapW = 0;
    // HashMap讀取時間
    static int hashMapR = 0;
    static int linkMapW = 0;
    static int linkMapR = 0;
    static int treeMapW = 0;
    static int treeMapR = 0;
    static int hashTableW = 0;
    static int hashTableR = 0;
 
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Test test = new Test();
            test.test(100 * 10000);
            System.out.println();
        }
 
        System.out.println("hashMapW = " + hashMapW / 10);
        System.out.println("hashMapR = " + hashMapR / 10);
        System.out.println("linkMapW = " + linkMapW / 10);
        System.out.println("linkMapR = " + linkMapR / 10);
        System.out.println("treeMapW = " + treeMapW / 10);
        System.out.println("treeMapR = " + treeMapR / 10);
        System.out.println("hashTableW = " + hashTableW / 10);
        System.out.println("hashTableR = " + hashTableR / 10);
    }
 
    public void test(int size) {
        int index;
        Random random = new Random();
        String[] key = new String[size];
 
        // HashMap 插入
        Map<String, String> map = new HashMap<String, String>();
        long start = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            key[i] = UUID.randomUUID().toString();
            map.put(key[i], UUID.randomUUID().toString());
        }
        long end = System.currentTimeMillis();
        hashMapW += (end - start);
        System.out.println("HashMap插入耗時 = " + (end - start) + " ms");
 
        // HashMap 讀取
        start = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            index = random.nextInt(size);
            map.get(key[index]);
        }
        end = System.currentTimeMillis();
        hashMapR += (end - start);
        System.out.println("HashMap讀取耗時 = " + (end - start) + " ms");
 
        // LinkedHashMap 插入
        map = new LinkedHashMap<String, String>();
        start = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            key[i] = UUID.randomUUID().toString();
            map.put(key[i], UUID.randomUUID().toString());
        }
        end = System.currentTimeMillis();
        linkMapW += (end - start);
        System.out.println("LinkedHashMap插入耗時 = " + (end - start) + " ms");
 
        // LinkedHashMap 讀取
        start = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            index = random.nextInt(size);
            map.get(key[index]);
        }
        end = System.currentTimeMillis();
        linkMapR += (end - start);
        System.out.println("LinkedHashMap讀取耗時 = " + (end - start) + " ms");
 
        // TreeMap 插入
        key = new String[size];
        map = new TreeMap<String, String>();
        start = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            key[i] = UUID.randomUUID().toString();
            map.put(key[i], UUID.randomUUID().toString());
        }
        end = System.currentTimeMillis();
        treeMapW += (end - start);
        System.out.println("TreeMap插入耗時 = " + (end - start) + " ms");
 
        // TreeMap 讀取
        start = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            index = random.nextInt(size);
            map.get(key[index]);
        }
        end = System.currentTimeMillis();
        treeMapR += (end - start);
        System.out.println("TreeMap讀取耗時 = " + (end - start) + " ms");
 
        // Hashtable 插入
        key = new String[size];
        map = new Hashtable<String, String>();
        start = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            key[i] = UUID.randomUUID().toString();
            map.put(key[i], UUID.randomUUID().toString());
        }
        end = System.currentTimeMillis();
        hashTableW += (end - start);
        System.out.println("Hashtable插入耗時 = " + (end - start) + " ms");
 
        // Hashtable 讀取
        start = System.currentTimeMillis();
        for (int i = 0; i < size; i++) {
            index = random.nextInt(size);
            map.get(key[index]);
        }
        end = System.currentTimeMillis();
        hashTableR += (end - start);
        System.out.println("Hashtable讀取耗時 = " + (end - start) + " ms");
    }
}

3.Map 遍歷

初始化數(shù)據(jù)

Map<String, String> map = new HashMap<String, String>();
map.put("key1", "value1");
map.put("key2", "value2");

增強for循環(huán)遍歷

使用keySet()遍歷

for (String key : map.keySet()) {
    System.out.println(key + " :" + map.get(key));
}

使用entrySet()遍歷

for (Map.Entry<String, String> entry : map.entrySet()) {
    System.out.println(entry.getKey() + " :" + entry.getValue());
}

迭代器遍歷

使用keySet()遍歷

Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
    String key = iterator.next();
    System.out.println(key + " :" + map.get(key));
}

使用entrySet()遍歷

Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
    Map.Entry<String, String> entry = iterator.next();
    System.out.println(entry.getKey() + "∠:" + entry.getValue());
}

HashMap四種便利方式性能比較

比較方式

分別對四種遍歷方式進行10W次迭代跟伏,比較用時。

代碼

package net.xsoftlab.baike;
 
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
 
public class TestMap {
 
    public static void main(String[] args) {
        // 初始化翩瓜,10W次賦值
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (int i = 0; i < 100000; i++)
            map.put(i, i);
 
        /** 增強for循環(huán)受扳,keySet迭代 */
        long start = System.currentTimeMillis();
        for (Integer key : map.keySet()) {
            map.get(key);
        }
        long end = System.currentTimeMillis();
        System.out.println("增強for循環(huán),keySet迭代 -> " + (end - start) + " ms");
 
        /** 增強for循環(huán)兔跌,entrySet迭代 */
        start = System.currentTimeMillis();
        for (Entry<Integer, Integer> entry : map.entrySet()) {
            entry.getKey();
            entry.getValue();
        }
        end = System.currentTimeMillis();
        System.out.println("增強for循環(huán)勘高,entrySet迭代 -> " + (end - start) + " ms");
 
        /** 迭代器,keySet迭代 */
        start = System.currentTimeMillis();
        Iterator<Integer> iterator = map.keySet().iterator();
        Integer key;
        while (iterator.hasNext()) {
            key = iterator.next();
            map.get(key);
        }
        end = System.currentTimeMillis();
        System.out.println("迭代器,keySet迭代 -> " + (end - start) + " ms");
 
        /** 迭代器华望,entrySet迭代 */
        start = System.currentTimeMillis();
        Iterator<Map.Entry<Integer, Integer>> iterator1 = map.entrySet().iterator();
        Map.Entry<Integer, Integer> entry;
        while (iterator1.hasNext()) {
            entry = iterator1.next();
            entry.getKey();
            entry.getValue();
        }
        end = System.currentTimeMillis();
 
        System.out.println("迭代器蕊蝗,entrySet迭代 -> " + (end - start) + " ms");
    }
}

運行三次,比較結果

第一次

增強for循環(huán)立美,keySet迭代 -> 37 ms
增強for循環(huán)匿又,entrySet迭代 -> 19 ms
迭代器,keySet迭代 -> 14 ms
迭代器建蹄,entrySet迭代 -> 9 ms

第二次
增強for循環(huán)碌更,keySet迭代 -> 29 ms
增強for循環(huán),entrySet迭代 -> 22 ms
迭代器洞慎,keySet迭代 -> 19 ms
迭代器痛单,entrySet迭代 -> 12 ms

第三次
增強for循環(huán),keySet迭代 -> 27 ms
增強for循環(huán)劲腿,entrySet迭代 -> 19 ms
迭代器旭绒,keySet迭代 -> 18 ms
迭代器,entrySet迭代 -> 10 ms

平均值
增強for循環(huán)焦人,keySet迭代 -> 31 ms
增強for循環(huán)挥吵,entrySet迭代 -> 20 ms
迭代器,keySet迭代 -> 17 ms
迭代器花椭,entrySet迭代 -> 10.33 ms

總結

  1. 增強for循環(huán)使用方便忽匈,但性能較差,不適合處理超大量級的數(shù)據(jù)矿辽。

  2. 迭代器的遍歷速度要比增強for循環(huán)快很多丹允,是增強for循環(huán)的2倍左右。

  3. 使用entrySet遍歷的速度要比keySet快很多袋倔,是keySet的1.5倍左右雕蔽。

4.Map 排序

HashMap、Hashtable宾娜、LinkedHashMap排序

注:

TreeMap也可以使用此方法進行排序批狐,但是更推薦下面的方法。

Map<String, String> map = new HashMap<String, String>();
map.put("a", "c");
map.put("b", "b");
map.put("c", "a");
 
// 通過ArrayList構造函數(shù)把map.entrySet()轉換成list
List<Map.Entry<String, String>> list = new ArrayList<Map.Entry<String, String>>(map.entrySet());
// 通過比較器實現(xiàn)比較排序
Collections.sort(list, new Comparator<Map.Entry<String, String>>() {
    public int compare(Map.Entry<String, String> mapping1, Map.Entry<String, String> mapping2) {
        return mapping1.getKey().compareTo(mapping2.getKey());
    }
});
 
for (Map.Entry<String, String> mapping : list) {
    System.out.println(mapping.getKey() + " :" + mapping.getValue());
}

TreeMap排序

TreeMap默認按key進行升序排序碳默,如果想改變默認的順序贾陷,可以使用比較器:

Map<String, String> map = new TreeMap<String, String>(new Comparator<String>() {
    public int compare(String obj1, String obj2) {
        return obj2.compareTo(obj1);// 降序排序
    }
});
map.put("a", "c");
map.put("b", "b");
map.put("c", "a");
 
for (String key : map.keySet()) {
    System.out.println(key + " :" + map.get(key));
}

按value排序(通用)

Map<String, String> map = new TreeMap<String, String>();
map.put("a", "c");
map.put("b", "b");
map.put("c", "a");

// 通過ArrayList構造函數(shù)把map.entrySet()轉換成list
List<Map.Entry<String, String>> list = new ArrayList<Map.Entry<String, String>>(map.entrySet());
// 通過比較器實現(xiàn)比較排序
Collections.sort(list, new Comparator<Map.Entry<String, String>>() {
    public int compare(Map.Entry<String, String> mapping1, Map.Entry<String, String> mapping2) {
        return mapping1.getValue().compareTo(mapping2.getValue());
    }
});

for (String key : map.keySet()) {
    System.out.println(key + " :" + map.get(key));
}        

5.常用API

方法 作用
clear() 從 Map 中刪除所有映射
remove(Object key) 從 Map 中刪除鍵和關聯(lián)的值
put(Object key, Object value) 將指定值與指定鍵相關聯(lián)
putAll(Map t) 將指定 Map 中的所有映射復制到此 map
entrySet() 返回 Map 中所包含映射的 Set 視圖。Set 中的每個元素都是一個 Map.Entry 對象嘱根,可以使用 getKey() 和 getValue() 方法(還有一個 setValue() 方法)訪問后者的鍵元素和值元素
keySet() 返回 Map 中所包含鍵的 Set 視圖髓废。刪除 Set 中的元素還將刪除 Map 中相應的映射(鍵和值)
values() 返回 map 中所包含值的 Collection 視圖。刪除 Collection 中的元素還將刪除 Map 中相應的映射(鍵和值)
get(Object key) 返回與指定鍵關聯(lián)的值
containsKey(Object key) 如果 Map 包含指定鍵的映射该抒,則返回 true
containsValue(Object value) 如果此 Map 將一個或多個鍵映射到指定值慌洪,則返回 true
isEmpty() 如果 Map 不包含鍵-值映射,則返回 true
size() 返回 Map 中的鍵-值映射的數(shù)目
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市冈爹,隨后出現(xiàn)的幾起案子涌攻,更是在濱河造成了極大的恐慌,老刑警劉巖频伤,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件恳谎,死亡現(xiàn)場離奇詭異,居然都是意外死亡憋肖,警方通過查閱死者的電腦和手機因痛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岸更,“玉大人鸵膏,你說我怎么就攤上這事≡醮叮” “怎么了谭企?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長评肆。 經(jīng)常有香客問我债查,道長,這世上最難降的妖魔是什么瓜挽? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任攀操,我火速辦了婚禮,結果婚禮上秸抚,老公的妹妹穿的比我還像新娘。我一直安慰自己歹垫,他們只是感情好剥汤,可當我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著排惨,像睡著了一般吭敢。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上暮芭,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天鹿驼,我揣著相機與錄音,去河邊找鬼辕宏。 笑死畜晰,一個胖子當著我的面吹牛,可吹牛的內容都是我干的瑞筐。 我是一名探鬼主播凄鼻,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了块蚌?” 一聲冷哼從身側響起闰非,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎峭范,沒想到半個月后财松,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡纱控,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年辆毡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片其徙。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡胚迫,死狀恐怖,靈堂內的尸體忽然破棺而出唾那,到底是詐尸還是另有隱情访锻,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布闹获,位于F島的核電站期犬,受9級特大地震影響,放射性物質發(fā)生泄漏避诽。R本人自食惡果不足惜龟虎,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沙庐。 院中可真熱鬧鲤妥,春花似錦、人聲如沸拱雏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铸抑。三九已至贡耽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間鹊汛,已是汗流浹背蒲赂。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留刁憋,地道東北人滥嘴。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像至耻,于是被迫代替她去往敵國和親氏涩。 傳聞我的和親對象是個殘疾皇子届囚,可洞房花燭夜當晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內容