一 、
TreeMap中的元素默认按照keys的自然排序排列。
(对Integer来说,其自然排序就是数字的升序;对String来说,其自然排序就是按照字母表排序)
案例一
@Test public void TreeMapTest1() { Map<Integer, Integer> map = new TreeMap<>();
map.put(3,8);
map.put(2,7);
map.put(1,9);
map.put(4,6);
System.out.println("map= "+map); }
案例二
@Test public void TreeMapTest2() { Map<Integer, String> map = new TreeMap<>();
map.put(3,"8");
map.put(2,"7");
map.put(1,"9");
map.put(4,"6");
System.out.println("map= "+map); }
案例三
@Test public void TreeMapTest3() { Map<Integer, String> map = new TreeMap<>(); map.put(3,"g"); map.put(2,"b"); map.put(1,"f"); map.put(4,"k"); System.out.println("map= "+map); }
案例四
@Test public void TreeMapTest3() { Map<String, Integer> map = new TreeMap<>(); map.put("g",4); map.put("b",1); map.put("f",2); map.put("k",3); System.out.println("map= "+map); }
案例五
@Test public void TreeMapTest4() { Map<String, String> map = new TreeMap<>(); map.put("g","c"); map.put("b","a"); map.put("f","d"); map.put("k","b"); System.out.println("map= "+map); }
结论一:由以上知道,对Integer来说,其自然排序就是数字的升序 指的是针对key来说的。
结论二:同理,对String来说,其自然排序就是按照字母表排序) 指的也是key来说。
二、Api的使用
TreeMap<Integer, String> treeMap = new TreeMap<>();
treeMap.put(1, "a");
treeMap.put(2, "b");
treeMap.put(3, "c");
treeMap.put(4, "d"); // treeMap: {1=a, 2=b, 3=c, 4=d}
treeMap.remove(4); // treeMap: {1=a, 2=b, 3=c}
int sizeOfTreeMap = treeMap.size(); // sizeOfTreeMap: 3
treeMap.replace(2, "e"); // treeMap: {1=a, 2=e, 3=c}
Map.Entry entry = treeMap.firstEntry(); // entry: 1 -> a
Integer key = treeMap.firstKey(); // key: 1
entry = treeMap.lastEntry(); // entry: 3 -> c
key = treeMap.lastKey(); // key: 3
String value = treeMap.get(3); // value: c
SortedMap sortedMap = treeMap.headMap(2); // sortedMap: {1=a}
sortedMap = treeMap.subMap(1, 3); // sortedMap: {1=a, 2=e}
Set setOfEntry = treeMap.entrySet(); // setOfEntry: [1=a, 2=e, 3=c]
Collection<String> values = treeMap.values(); // values: [a, e, c]
treeMap.forEach((integer, s) -> System.out.println(integer + "->" + s));
// output:
// 1 -> a
// 2 -> e
// 3 -> c
三、多线程问题
案例一 线程不安全
@Test public void TreeMapTest5() throws InterruptedException { Map<String, Integer> map = new TreeMap<>(); //线程T-1 new Thread(() -> { System.out.println("当前线程:" + Thread.currentThread().getName()); for (int i = 1; i <500; i++) { map.put("a" + i, i); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }, "T-1").start(); //线程T-2 new Thread(() -> { System.out.println("当前线程:" + Thread.currentThread().getName()); for (int i = 500; i <=1000; i++) { map.put("a" + i, i); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }, "T-2").start(); //线程T-3 new Thread(() -> { System.out.println("当前线程:" + Thread.currentThread().getName()); for (int i = 500; i <=1000; i++) { if(map.containsKey("a100")){ map.replace("a100",888); } try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }, "T-3").start(); Thread.sleep(1000); System.out.println("a100= "+map.get("a100")); System.out.println("大小:" + map.size()); }
案例二 线程安全
@Test public void TreeMapTest5() throws InterruptedException { //Map<String, Integer> map = new TreeMap<>(); Map<String, Integer> map = new ConcurrentSkipListMap<>(); //线程T-1 new Thread(() -> { System.out.println("当前线程:" + Thread.currentThread().getName()); for (int i = 1; i <500; i++) { map.put("a" + i, i); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }, "T-1").start(); //线程T-2 new Thread(() -> { System.out.println("当前线程:" + Thread.currentThread().getName()); for (int i = 500; i <=1000; i++) { map.put("a" + i, i); try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }, "T-2").start(); //线程T-3 new Thread(() -> { System.out.println("当前线程:" + Thread.currentThread().getName()); for (int i = 500; i <=1000; i++) { if(map.containsKey("a100")){ map.replace("a100",888); } try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } }, "T-3").start(); Thread.sleep(1000); System.out.println("a100= "+map.get("a100")); System.out.println("大小:" + map.size()); }
四、 常用方法
增添元素
V put(K key, V value)
:将指定映射放入该TreeMap中V putAll(Map map)
:将指定map放入该TreeMap中
删除元素
void clear()
:清空TreeMap中的所有元素V remove(Object key)
:从TreeMap中移除指定key对应的映射
修改元素
V replace(K key, V value)
:替换指定key对应的value值boolean replace(K key, V oldValue, V newValue)
:当指定key的对应的value为指定值时,替换该值为新值-
查找元素
boolean containsKey(Object key)
:判断该TreeMap中是否包含指定key的映射boolean containsValue(Object value)
:判断该TreeMap中是否包含有关指定value的映射Map.Entry<K, V> firstEntry()
:返回该TreeMap的第一个(最小的)映射K firstKey()
:返回该TreeMap的第一个(最小的)映射的keyMap.Entry<K, V> lastEntry()
:返回该TreeMap的最后一个(最大的)映射K lastKey()
:返回该TreeMap的最后一个(最大的)映射的keyv get(K key)
:返回指定key对应的valueSortedMap<K, V> headMap(K toKey)
:返回该TreeMap中严格小于指定key的映射集合SortedMap<K, V> subMap(K fromKey, K toKey)
:返回该TreeMap中指定范围的映射集合(大于等于fromKey,小于toKey)
遍历接口
Set<Map<K, V>> entrySet()
:返回由该TreeMap中的所有映射组成的Set对象void forEach(BiConsumer<? super K,? super V> action)
:对该TreeMap中的每一个映射执行指定操作Collection<V> values()
:返回由该TreeMap中所有的values构成的集合
其他方法
Object clone()
:返回TreeMap实例的浅拷贝Comparator<? super K> comparator()
:返回给该TreeMap的keys排序的comparator,若为自然排序则返回nullint size()
:返回该TreepMap中包含的映射的数量
补充:如何选择合适的Map
- HashMap可实现快速存储和检索,但其缺点是其包含的元素是无序的,这导致它在存在大量迭代的情况下表现不佳。
- LinkedHashMap保留了HashMap的优势,且其包含的元素是有序的。它在有大量迭代的情况下表现更好。
- TreeMap能便捷的实现对其内部元素的各种排序,但其一般性能比前两种map差。
LinkedHashMap映射减少了HashMap排序中的混乱,且不会导致TreeMap的性能损失。