一、Map的用法:

1. 类型介绍:Java自带了各种 Map 类,这些 Map 类可以归为三种类型:

(1) 通用 Map:用于在应用程序中管理映射,通常在 java.util 程序包中实现;分别是:HashMap、HashTable、Properties、LinkedHashMap、IdentityHashMap、TreeMap、WeakHashMap、ConcurrentHashMap;

(2) 专用 Map:通常使用者不必亲自创建此类 Map,而是通过某些其他类对其进行访问:

             java.util.jar.Attributes、javax.print.attribute.standard.PrinterStateReasons、java.security.Provider、java.awt.RenderingHints、javax.swing.UIDefaults;

(3) 自行实现 Map:一个用于帮助我们实现自己的 Map 类的抽象类 AbstractMap;

二、部分常用类型的区别:

(1) HashMap:HashMap是最常用的 Map,它根据键的 HashCode 值存储数据,根据键可以直接获取其对应的值;具有很快的访问速度。HashMap 最多只允许一条记录的键为 null(多条将会依次覆盖);允许多条记录的值为 null。非同步的。

(2) TreeMap:能够把它保存的记录根据键 (key) 排序,默认是按升序排序,也可以指定排序的比较器,当用 Iterator 遍历 TreeMap 时,得到的记录是排序过的。TreeMap 不允许 key 的值为 null。非同步的。

(3) HashTable:与 HashMap 类似,不同的是,key 和 value 的值均不允许为 null;它支持线程的同步,即,任一时刻只有一个线程能写 HashTable,因此也导致了 HashTable 在写入时会比较慢。

(4) LinkedHashMap:保存了记录的插入顺序,在用 Iterator 遍历 LinkedHashMap 时,先得到的记录肯定是先插入的。在遍历的时候会比 HashMap 慢。key 和 value 均允许为 null。非同步的 。

三、Map 初始化及增、删、获取、清空元素:

// 初始化 Map
Map<String, String> map = new HashMap<String, String>();
// 插入元素
map.put("key1", "value1");
map.put("key2", "value2");  
// 获取元素
map.get("key1");
// 删除元素
map.remove("key2");
// 清空map
map.clear();

四、四种常用 Map 插入与获取性能比较:

       测试比较代码:

import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap;
import java.util.UUID;

public class MainTestClass {
	static int hashMap_W = 0;
	static int hashMap_R = 0;
	static int linkedHashMap_W = 0;
	static int linkedHashMap_R = 0;
	static int treeMap_W = 0;
	static int treeMap_R = 0;
	static int hashTable_W = 0;
	static int hashTable_R = 0;

	public static void main(String[] args) {
		for(int i=0; i<10; i++){
			MainTestClass mtc = new MainTestClass();
			mtc.testMethod(100 * 10000);
			System.out.println();
		}
		System.out.println("hashMap_W = " + hashMap_W / 10);
		System.out.println("hashMap_R = " + hashMap_R / 10);
		System.out.println("linkedHashMap_W = " + linkedHashMap_W / 10);
		System.out.println("linkedHashMap_R = " + linkedHashMap_R / 10);
		System.out.println("treeMap_W = " + treeMap_W / 10);
		System.out.println("treeMap_R = " + treeMap_R / 10);
		System.out.println("hashTable_W = " + hashTable_W / 10);
		System.out.println("hashTable_R = " + hashTable_R / 10);
	}

	public void testMethod(int size){
		int index;
		Random rand = 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();
		hashMap_W += (end - start);
		System.out.println("HashMap插入数据耗时 = " + (end - start) + "ms");
		
		// HashMap 获取数据
		start = System.currentTimeMillis();
		for(int i=0; i<size; i++){
			index = rand.nextInt(size);
			map.get(key[index]);
		}
		end = System.currentTimeMillis();
		hashMap_R += (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();
		linkedHashMap_W += (end - start);
		System.out.println("LinkedHashMap插入数据耗时 = " + (end - start) + "ms");
		
		// LinkedHashMap 获取数据
		start = System.currentTimeMillis();
		for(int i=0; i<size; i++){
			index = rand.nextInt(size);
			map.get(key[index]);
		}
		end = System.currentTimeMillis();
		linkedHashMap_R += (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();
		treeMap_W += (end - start);
		System.out.println("TreeMap插入数据耗时 = " + (end - start) + "ms");
		
		// TreeMap 获取数据
		start = System.currentTimeMillis();
		for(int i=0; i<size; i++){
			index = rand.nextInt(size);
			map.get(key[index]);
		}
		end = System.currentTimeMillis();
		treeMap_R += (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();
		hashTable_W += (end - start);
		System.out.println("Hashtable插入数据耗时 = " + (end - start) + "ms");
		
		// HashTable 获取数据
		start = System.currentTimeMillis();
		for(int i=0; i<size; i++){
			index = rand.nextInt(size);
			map.get(key[index]);
		}
		end = System.currentTimeMillis();
		hashTable_R += (end - start);
		System.out.println("Hashtable获取数据耗时 = " + (end - start) + "ms");
	}
}

测试:分别向四种Map集合中插入/取出1W条、10W条、100W条数据,每一数据量循环10次,分别取十次的平均时间;分别测试两轮,测试结果如下表所示(单位为:ms):

插入10次平均时间(ms):

map声明时赋值java java中map用法_java

1W

10W

100W

第一轮

第二轮

第一轮

第二轮

第一轮

第二轮

HashMap

69

57

252

226

2249

2272

LinkedHashMap

22

18

190

193

2220

2233

TreeMap

25

21

267

248

2805

2859

Hashtable

21

18

185

171

2134

2068

获取10次平均时间(ms) :

map声明时赋值java java中map用法_迭代_02

1W

10W

100W

第一轮

第二轮

第一轮

第二轮

第一轮

第二轮

HashMap

1

1

16

15

198

202

LinkedHashMap

1

1

15

15

191

192

TreeMap

5

4

92

96

1078

1069

Hashtable

1

1

16

17

206

225

五、Map 遍历方法:

       初始化数据:

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

(1) 增强 for 循环遍历

      ① 使用 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());
}

(2) 迭代器遍历

      ① 使用 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 com.sztxtech.testmap;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;

/**
 * 测试Map遍历速度
 */
public class TestMapSpeed {

	public static void main(String[] args) {
		// 初始化Map,并进行10W次赋值
		Map<Integer, String> map = new HashMap<Integer, String>();
		for (int i = 0; i < 100000; i++) {
			map.put(i, UUID.randomUUID().toString());
		}
		long start = System.currentTimeMillis();
		/* 增强for循环,keySet迭代 */
		for(Integer key : map.keySet()){
			map.get(key);
		}
		long end = System.currentTimeMillis();
		System.out.println("增强 for 循环,keySet 迭代 --> "+(end-start)+"ms");
		
		/* 增强for循环,entrySet迭代 */
		start = System.currentTimeMillis();
		for(Entry<Integer, String> entry : map.entrySet()){
			entry.getKey();
			entry.getValue();
		}
		end = System.currentTimeMillis();
		System.out.println("增强 for 循环,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, String>> iterators = map.entrySet().iterator();
		Map.Entry<Integer, String> entry;
		while(iterators.hasNext()){
			entry = iterators.next();
			entry.getKey();
			entry.getValue();
		}
		end = System.currentTimeMillis();
		System.out.println("迭代器,entrySet迭代 --> "+(end-start)+"ms");
	}
}

以上测试代码分别运行三次的测试结果如下:

遍历方式

第一次

第二次

第三次

增强for循环,keySet迭代

 13ms

10ms

10ms

增强for循环,entrySet迭代

 7ms

5ms

4ms

迭代器,keySet迭代

 3ms

6ms

7ms

迭代器,entrySet迭代

 3ms

2ms

4ms

根据以上测试结果得出结论:

① 增强 for 循环使用方便,但性能较差,不适合处理超大量级的数据;

② 迭代器的遍历速度要比增强 for 循环快很多,是增强 for 循环的 2 倍左右;

③ 使用 entrySet 遍历的速度要比 keySet 快很多,是 keySet 的 1.5 倍左右;

七、Map 排序

        (1) HashMap、Hashtable、LinkedHashMap 排序;

        注:TreeMap 也可以使用此方法进行排序,但是更推荐下面的方法:

Map<String, String> map = new HashMap<String, String>();
map.put("cccc", "aaaa");
map.put("bbbb", "bbbb");
map.put("aaaa", "cccc");
map.put("eeee", "dddd");
map.put("dddd", "ffff");

// 通过 ArrayList 构造函数将 map.entrySet() 转换为 list
List<Map.Entry<String, String>> list = new ArrayList<Map.Entry<String, String>>(map.entrySet());
// 通过比较器实现比较排序
Collections.sort(list, new Comparator<Map.Entry<String, String>>(){
    @Override
    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());
}

         (2) TreeMap 排序;

               TreeMap 默认按 key 进行升序排序,如果想改变默认的顺序,可以使用比较器:

Map<String, String> map = new TreeMap<String, String>(new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
		return o2.compareTo(o1);// 降序排序
//		return o1.compareTo(o2);// 升序排序
    }
});

map.put("cccc", "aaaa");
map.put("bbbb", "bbbb");
map.put("aaaa", "cccc");
map.put("eeee", "dddd");
map.put("dddd", "ffff");
for(String key : map.keySet()) {
    System.out.println(key + " : " + map.get(key));
}

         (2) 按 value 排序,通用方法;

Map<String, String> map = new TreeMap<String, String>();
map.put("张三", "dddd");
map.put("李四", "cccc");
map.put("王五", "ffff");
map.put("马六", "bbbb");
// 通过 ArrayList 构造函数将 map.entrySet() 转换成 list
List<Entry<String, String>> list = new ArrayList<Entry<String, String>>(map.entrySet());
// 通过比较器实现比较排序
Collections.sort(list, new Comparator<Map.Entry<String, String>>() {
    @Override
    public int compare(Entry<String, String> o1, Entry<String, String> o2) {
	    // TODO Auto-generated method stub
		return o1.getValue().compareTo(o2.getValue());
	}
});
for(Entry<String, String> entry : list) {
	System.out.println(entry.getKey() + " : " + entry.getValue());
}

八、常用 API

Java 中 Map 常用 API

方法

描述

clear()

从 Map 中删除/清空所有映射

remove(Object key)

从 Map 中删除键所对应的值

put(Object key, Object value)

将指定的值与键相关联并存入 Map

putAll(Map map)

将指定的 Map 中的所有映射复制到新的 Map 中

entrySet()

返回 Map 中所包含映射的 Set 视图。Set 中的每个元素都是一个 Map.Entry 对象,可以使用 getKey() 和 getValue()方法(还有一个 setValue()方法)访问后者的键元素和值元素

keySet()

返回 Map 中所包含键的 Set 视图。删除 Set 中的元素也将删除 Map 中相应的映射(键值对)

values()

返回 Map 中所包含值的 Collection 视图。删除 Collection 中的元素也将删除 Map 中相应的映射(键值对)

get(Object key)

返回与指定键所关联的映射

containsKey(Object key)

如果 Map 包含指定键的映射,则返回 true

containsValue(Object value)

如果此 Map 将一个或多个键映射到指定的值,则返回 true

isEmpty()

如果 Map 没有任何键-值映射,则返回 true

size()

返回 Map 中的键-值映射的数目