轉載 Java 集合系列12之 TreeMap詳細介紹(源碼解析)和使用示例
一、TreeMap 簡單介紹
什么是Map?
在數組中我們通過數組下標來對數組內容進行索引的,而在Map中我們通過對象來對 對象進行索引,用來索引的對象叫做key,其對應的對象叫做value。這就是我們平時說的鍵值對。
什么是TreeMap?
TreeMap是一個有序的key-value集合,是非線程安全的,基於紅黑樹(Red-Black tree)實現。其映射根據鍵的自然順序進行排序,或者根據創建映射時提供的 Comparator 進行排序,具體取決於使用的構造方法。其基本操作 containsKey、get、put 和 remove 的時間復雜度是 log(n) 。TreeMap是非同步的。 它的iterator 方法返回的迭代器是fail-fastl的。
當自定義比較器時,需要自定義類實現java.lang.Comparable接口,並重寫compareTo()方法。
TreeMap與HashMap的區別:
- 數據結構不同:
- HashMap是基於哈希表,由 數組+鏈表+紅黑樹 構成。
- TreeMap是基於紅黑樹實現。
- 存儲方式不同:
- HashMap是通過key的hashcode對其內容進行快速查找。
- TreeMap中所有的元素都保持着某種固定的順序。
- 排列順序:
- HashMap存儲順序不固定。
- TreeMap存儲順序固定,可以得到一個有序的結果集。
二、TreeMap源碼分析
1.TreeMap類繼承圖:
TreeMap類定義:
public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, java.io.Serializable
- TreeMap<K,V>:TreeMap是以key-value形式存儲數據的。
- extends AbstractMap<K,V>:繼承了AbstractMap,大大減少了實現Map接口時需要的工作量。
- implements NavigableMap<K,V>:實現了SortedMap,支持一系列的導航方法。比如返回有序的key集合。
- implements Cloneable:表明其可以調用克隆方法clone()來返回實例的field-for-field拷貝。
- implements Serializable:表明該類是可以序列化的。
2.類成員變量和靜態內部類Entry:
// 比較器對象 private final Comparator<? super K> comparator; // 根節點 private transient Entry<K,V> root; // 集合大小 private transient int size = 0; // 樹結構被修改的次數 private transient int modCount = 0;
// 紅黑樹節點顏色
private static final boolean RED = false;
private static final boolean BLACK = true;
// 靜態內部類用來表示節點類型 static final class Entry<K,V> implements Map.Entry<K,V> { K key; // 鍵 V value; // 值 Entry<K,V> left; // 指向左子樹的引用(指針) Entry<K,V> right; // 指向右子樹的引用(指針) Entry<K,V> parent; // 指向父節點的引用(指針) boolean color = BLACK; }
關鍵字transient的作用:
transient是Java語言的關鍵字,它被用來表示一個域中不是該對象串行化的一部分。
Java的 serialization 提供了一種持久化對象實例的機制。當持久化對象時,可能有一個特殊的對象數據成員,我們不想用serialization機制來保存它。為了在一個特定對象的一個域上關閉serialization,可以在這個域前加上關鍵字transient。
當一個對象被串行化的時候,transient型的變量值 不包括在串行化的表示中,而 非transient型的變量 是被包括進去的。
3.TreeMap的構造函數:
// 默認構造函數。使用默認比較器比較key的大小,TreeMap中的元素按照自然排序進行排列。 public TreeMap() {
// 默認比較機制 comparator = null; } // 帶比較器的構造函數 public TreeMap(Comparator<? super K> comparator) { this.comparator = comparator; } // 帶Map的構造函數,Map會成為TreeMap的子集 public TreeMap(Map<? extends K, ? extends V> m) { comparator = null; putAll(m); } // 帶SortedMap的構造函數,SortedMap會成為TreeMap的子集 public TreeMap(SortedMap<K, ? extends V> m) {
// 使用已知對象的比較器 comparator = m.comparator(); try { buildFromSorted(m.size(), m.entrySet().iterator(), null, null); } catch (java.io.IOException cannotHappen) { } catch (ClassNotFoundException cannotHappen) { } }
putAll(Map<? extends K, ? extends V> map) 方法:
/** * Map中的所有元素添加到TreeMap中 */ public void putAll(Map<? extends K, ? extends V> map) { int mapSize = map.size(); // TreeMap的size為0,map的size不為0,並且map是SortedMap的實例 if (size==0 && mapSize!=0 && map instanceof SortedMap) { Comparator<?> c = ((SortedMap<?,?>)map).comparator(); // 默認比較器等於map的比較器,或者map的比較器不為null,並且與默認比較器相等 if (c == comparator || (c != null && c.equals(comparator))) { ++modCount; try { buildFromSorted(mapSize, map.entrySet().iterator(), null, null); } catch (java.io.IOException cannotHappen) { } catch (ClassNotFoundException cannotHappen) { } return; } } // 使用父類putAll() super.putAll(map); } /** * Map中的所有元素添加到TreeMap中 */ public void putAll(Map<? extends K, ? extends V> m) { // 遍歷map一個一個添加到TreeMap中 for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) put(e.getKey(), e.getValue()); }
buildFromSorted(int size, Iterator<?> it, java.io.ObjectInputStream str, V defaultVal) 方法:
/** * SortedMap(有序的map)中的所有元素添加到TreeMap中 */ private void buildFromSorted(int size, Iterator<?> it, java.io.ObjectInputStream str, V defaultVal) throws java.io.IOException, ClassNotFoundException { this.size = size; root = buildFromSorted(0, 0, size-1, computeRedLevel(size), it, str, defaultVal); } /** * 將map中的元素逐個添加到TreeMap中,並返回map的中間元素作為根節點 */ private final Entry<K,V> buildFromSorted(int level, int lo, int hi, int redLevel, Iterator<?> it, java.io.ObjectInputStream str, V defaultVal) throws java.io.IOException, ClassNotFoundException { if (hi < lo) return null; // 獲取中間元素 int mid = (lo + hi) >>> 1; Entry<K,V> left = null; // 若lo小於mid,則遞歸調用獲取(middel的)左孩子。 if (lo < mid) left = buildFromSorted(level+1, lo, mid - 1, redLevel, it, str, defaultVal); // 從Iterator或stream中獲取middle節點對應的key和value K key; V value; if (it != null) { if (defaultVal==null) { Map.Entry<?,?> entry = (Map.Entry<?,?>)it.next(); key = (K)entry.getKey(); value = (V)entry.getValue(); } else { key = (K)it.next(); value = defaultVal; } } else { // use stream key = (K) str.readObject(); value = (defaultVal != null ? defaultVal : (V) str.readObject()); } // 創建middle節點 Entry<K,V> middle = new Entry<>(key, value, null); // 若當前節點的深度==紅色節點的深度,則將節點着色為紅色 if (level == redLevel) middle.color = RED; // 設置middle為left的父親,left為middle的左孩子 if (left != null) { middle.left = left; left.parent = middle; } if (mid < hi) { // 遞歸調用獲取(middel的)右孩子 Entry<K,V> right = buildFromSorted(level+1, mid+1, hi, redLevel, it, str, defaultVal); // 設置middle為right的父親,right為middle的右孩子 middle.right = right; right.parent = middle; } return middle; }
添加到紅黑樹中時,只將level == redLevel的節點設為紅色。表示第level級節點,實際上是用buildFromSorted方法轉換成紅黑樹后 的最底端的節點(假設根節點在最上方);只將紅黑樹最底端的級別 着色為紅色,其余都是黑色。
4.核心方法:
紅黑樹相關的方法:
rotateLeft(Entry<K,V> p) 方法:
/** * 左旋 */ private void rotateLeft(Entry<K,V> p) { if (p != null) { Entry<K,V> r = p.right; // 令p節點右孩子為r節點 p.right = r.left; // 令r節點的左孩子為 p節點的右孩子 if (r.left != null) r.left.parent = p; // 當r節點的左孩子不為null時,令p節點為 r節點的左孩子 的父節點 r.parent = p.parent; // 令p節點的父節點為 r節點的父節點 if (p.parent == null) root = r; // 當p節點的父節點為null時,令r節點為根節點 else if (p.parent.left == p) p.parent.left = r; // 當p節點的父節點的左孩子為p節點時,令r節點為 p節點的父節點的左孩子 else p.parent.right = r; // 當p節點的父節點的右孩子為p節點時,令r節點為 p節點的父節點的右孩子 r.left = p; // 令p節點為 r節點的左孩子 p.parent = r; // 令r節點為 p節點的父節點 } }
put(K key, V value) 方法:
/** * 插入操作 */ public V put(K key, V value) { Entry<K,V> t = root; // 獲取根節點 if (t == null) { compare(key, key); // 檢查key的類型,是否為null root = new Entry<>(key, value, null); size = 1; modCount++; return null; } int cmp; Entry<K,V> parent; // 獲取比較器 Comparator<? super K> cpr = comparator; // 比較器不為null時,即自定義了比較器 if (cpr != null) { // 循環比較插入節點的key與根節點的key的大小,確定插入節點的位置,即找到插入節點的父節點 do { parent = t; cmp = cpr.compare(key, t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); // 插入節點與根節點的key的大小相同,直接覆蓋 } while (t != null); } // 比較器為null時,使用默認的比較器 else { if (key == null) throw new NullPointerException(); @SuppressWarnings("unchecked") Comparable<? super K> k = (Comparable<? super K>) key; // 循環比較插入節點的key與根節點的key的大小,確定插入節點的位置,即找到插入節點的父節點 do { parent = t; cmp = k.compareTo(t.key); if (cmp < 0) t = t.left; else if (cmp > 0) t = t.right; else return t.setValue(value); } while (t != null); } // 在插入節點的父節點后創建節點 Entry<K,V> e = new Entry<>(key, value, parent); if (cmp < 0) parent.left = e; else parent.right = e; // 插入修正操作,使插入節點后,TreeMap還是紅黑樹結構 fixAfterInsertion(e); size++; modCount++; return null; }
與紅黑樹有關的方法還有:
- 右旋-rotateRight(Entry<K,V> p)
- 插入修正為紅黑樹-fixAfterInsertion(Entry<K,V> x)
- 刪除-deleteEntry(Entry<K,V> p)
- 刪除修正為紅黑樹-fixAfterDeletion(Entry<K,V> x)
都是根據算法翻譯成代碼,具體可參考這里。
TreeMap中Entry相關的方法:
TreeMap的 firstEntry()、 lastEntry()、 lowerEntry()、 higherEntry()、 floorEntry()、 ceilingEntry()、 pollFirstEntry() 、 pollLastEntry() 原理類似,以下講解firstEntry()方法。
firstEntry() 方法:
/** * 獲取第一個節點 */ public Map.Entry<K,V> firstEntry() { return exportEntry(getFirstEntry()); } /** * 獲取第一個節點 */ final Entry<K,V> getFirstEntry() { // 獲取根節點 Entry<K,V> p = root; if (p != null) while (p.left != null) p = p.left; return p; } /** * 獲取第一個節點 */ static <K,V> Map.Entry<K,V> exportEntry(TreeMap.Entry<K,V> e) { // 如果節點為null,創建AbstractMap.SimpleImmutableEntry類型的對象,並返回 return (e == null) ? null : new AbstractMap.SimpleImmutableEntry<>(e); }

public static class SimpleImmutableEntry<K,V> implements Entry<K,V>, java.io.Serializable { private static final long serialVersionUID = 7138329143949025153L; private final K key; private final V value; public SimpleImmutableEntry(K key, V value) { this.key = key; this.value = value; } public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) { this.key = entry.getKey(); this.value = entry.getValue(); } public K getKey() { return key; } public V getValue() { return value; } public V setValue(V value) { throw new UnsupportedOperationException(); } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> e = (Map.Entry<?,?>)o; return eq(key, e.getKey()) && eq(value, e.getValue()); } public int hashCode() { return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()); } public String toString() { return key + "=" + value; } }
從上面,我們可以看出 firstEntry() 和 getFirstEntry() 都是用於獲取第一個節點。但是,firstEntry() 是對外接口; getFirstEntry() 是內部接口。而且,firstEntry() 是通過 getFirstEntry() 來實現的。那為什么外界不能直接調用 getFirstEntry(),而需要多此一舉的調用 firstEntry() 呢?
這么做的目的是:防止用戶修改返回的Entry。getFirstEntry()返回的Entry是可以被修改的,但是經過firstEntry()返回的Entry不能被修改,只可以讀取Entry的key值和value值。因為exportEntry()方法所在類 SimpleImmutableEntry 的 setValue()方法會拋出 UnsupportedOperationException() 異常。
TreeMap中key相關方法:
TreeMap的firstKey()、lastKey()、lowerKey()、higherKey()、floorKey()、ceilingKey()原理都是類似的,下面以ceilingKey()來進行詳細說明。
ceilingKey(K key) 方法:
/** * 獲取大於/等於key的最小節點所對應的key,沒有的話返回null */ public K ceilingKey(K key) { return keyOrNull(getCeilingEntry(key)); } /** * 尋找大於/等於key的最小節點 */ final Entry<K,V> getCeilingEntry(K key) { Entry<K,V> p = root; while (p != null) { int cmp = compare(key, p.key); // 如果根節點的key大於給定key if (cmp < 0) { if (p.left != null) p = p.left; else return p; } else if (cmp > 0) { // 如果根節點的key小於給定key if (p.right != null) { p = p.right; } else { // 如果根節點的右孩子為null Entry<K,V> parent = p.parent; Entry<K,V> ch = p; while (parent != null && ch == parent.right) { ch = parent; parent = parent.parent; } return parent; } } else return p; } return null; } /** * 如果節點不為null,返回節點的key值,否則返回null */ static <K,V> K keyOrNull(TreeMap.Entry<K,V> e) { return (e == null) ? null : e.key; }
TreeMap中value()方法:
value() 方法返回 TreeMap中值的集合:
/** * 通過 new Values() 來實現,返回TreeMap中值的集合 * Values() 是集合類Value的構造函數 */ public Collection<V> values() { Collection<V> vs = values; if (vs == null) { vs = new Values(); values = vs; } return vs; } /** * 集合類Value */ class Values extends AbstractCollection<V> { // 返回迭代器 public Iterator<V> iterator() { // iterator() 通過ValueIterator() 返回迭代器 return new ValueIterator(getFirstEntry()); } // 返回個數 public int size() { return TreeMap.this.size(); } // TreeMap的值的集合中 是否包含 對象o public boolean contains(Object o) { return TreeMap.this.containsValue(o); } // 刪除TreeMap的值的集合中的對象o public boolean remove(Object o) { for (Entry<K,V> e = getFirstEntry(); e != null; e = successor(e)) { if (valEquals(e.getValue(), o)) { deleteEntry(e); return true; } } return false; } // 清空TreeMap的值的集合 public void clear() { TreeMap.this.clear(); } public Spliterator<V> spliterator() { return new ValueSpliterator<K,V>(TreeMap.this, null, null, 0, -1, 0); } } /** * ValueIterator類實現 Iterator接口實現的next()方法 */ final class ValueIterator extends PrivateEntryIterator<V> { ValueIterator(Entry<K,V> first) { super(first); } public V next() { return nextEntry().value; } }

/** * PrivateEntryIterator類實現 Iterator接口的hasNext()和remove()方法 * ValueIterator類實現 Iterator接口實現的next()方法 */ abstract class PrivateEntryIterator<T> implements Iterator<T> { // 下一節點 Entry<K,V> next; // 上一次返回的節點 Entry<K,V> lastReturned; // 修改次數統計數 int expectedModCount; PrivateEntryIterator(Entry<K,V> first) { expectedModCount = modCount; lastReturned = null; next = first; } // 是否存在下一個節點 public final boolean hasNext() { return next != null; } // 返回下一個節點 final Entry<K,V> nextEntry() { Entry<K,V> e = next; if (e == null) throw new NoSuchElementException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); next = successor(e); lastReturned = e; return e; } // 返回上一節點 final Entry<K,V> prevEntry() { Entry<K,V> e = next; if (e == null) throw new NoSuchElementException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); next = predecessor(e); lastReturned = e; return e; } // 刪除當前節點 public void remove() { if (lastReturned == null) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); // deleted entries are replaced by their successors if (lastReturned.left != null && lastReturned.right != null) next = lastReturned; deleteEntry(lastReturned); expectedModCount = modCount; lastReturned = null; } }
TreeMap的entrySet()方法:
entrySet() 方法返回 TreeMap的鍵值對的集合:
/** * 通過 new EntrySet() 來實現,返回TreeMap的鍵值對集合 */ public Set<Map.Entry<K,V>> entrySet() { EntrySet es = entrySet; return (es != null) ? es : (entrySet = new EntrySet()); } /** * EntrySet是TreeMap的所有鍵值對組成的集合,它的單位是單個鍵值對 */ class EntrySet extends AbstractSet<Map.Entry<K,V>> { // 返回迭代器 public Iterator<Map.Entry<K,V>> iterator() { return new EntryIterator(getFirstEntry()); } // EntrySet中是否包含 鍵值對Object public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> entry = (Map.Entry<?,?>) o; Object value = entry.getValue(); Entry<K,V> p = getEntry(entry.getKey()); return p != null && valEquals(p.getValue(), value); } // 刪除EntrySet中的 鍵值對Object public boolean remove(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry<?,?> entry = (Map.Entry<?,?>) o; Object value = entry.getValue(); Entry<K,V> p = getEntry(entry.getKey()); if (p != null && valEquals(p.getValue(), value)) { deleteEntry(p); return true; } return false; } // 返回EntrySet中元素個數 public int size() { return TreeMap.this.size(); } // 清空EntrySet public void clear() { TreeMap.this.clear(); } public Spliterator<Map.Entry<K,V>> spliterator() { return new EntrySpliterator<K,V>(TreeMap.this, null, null, 0, -1, 0); } } /** * EntryIterator類實現 Iterator接口實現的next()方法 */ final class EntryIterator extends PrivateEntryIterator<Map.Entry<K,V>> { EntryIterator(Entry<K,V> first) { super(first); } public Map.Entry<K,V> next() { return nextEntry(); } }
TreeMap實現的Cloneable接口:
TreeMap實現了Cloneable接口,即實現了clone()方法。
clone()方法的作用很簡單,就是克隆一個TreeMap對象並返回。
/** * 克隆一個TreeMap,並返回Object對象 */ public Object clone() { TreeMap<K,V> clone = null; try { clone = (TreeMap<K,V>) super.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(); } // Put clone into "virgin" state (except for comparator) clone.root = null; clone.size = 0; clone.modCount = 0; clone.entrySet = null; clone.navigableKeySet = null; clone.descendingMap = null; // Initialize clone with our mappings try { clone.buildFromSorted(size, entrySet().iterator(), null, null); } catch (java.io.IOException cannotHappen) { } catch (ClassNotFoundException cannotHappen) { } return clone; }
TreeMap實現的Serializable接口:
TreeMap實現java.io.Serializable,分別實現了串行讀取和寫入功能:
- 串行寫入函數是writeObject(),它的作用是將TreeMap的“容量和所有的Entry”都寫入到輸出流中。
- 串行讀取函數是readObject(),它的作用是將TreeMap的“容量和所有的Entry”依次讀出。
readObject() 和 writeObject() 正好是一對,通過它們,我能實現TreeMap的串行傳輸。
/** * java.io.Serializable的寫入函數 * 將TreeMap的 容量和所有的Entry 都寫入到輸出流中 */ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Write out the Comparator and any hidden stuff s.defaultWriteObject(); // Write out size (number of Mappings) s.writeInt(size); // Write out keys and values (alternating) for (Iterator<Map.Entry<K,V>> i = entrySet().iterator(); i.hasNext(); ) { Map.Entry<K,V> e = i.next(); s.writeObject(e.getKey()); s.writeObject(e.getValue()); } } /** * java.io.Serializable的讀取函數:根據寫入方式讀出 * 將TreeMap的 容量和所有的Entry 依次讀出 */ private void readObject(final java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in the Comparator and any hidden stuff s.defaultReadObject(); // Read in size int size = s.readInt(); buildFromSorted(size, null, s, null); }
三、TreeMap使用例子
1.TreeMap常用方法使用Demo:

import java.util.*; /** * @author nana * @date 2019/2/23 */ public class TreeMapDemo { public static void main(String[] args) { // 測試常用的API testTreeMapOrdinaryAPIs(); // 測試TreeMap導航函數 testNavigableMapAPIs(); // 測試TreeMap的子Map函數 testSubMapAPIs(); } /** * 測試常用的API */ private static void testTreeMapOrdinaryAPIs() { // 生成隨機數 Random random = new Random(); // 創建TreeMap實例 TreeMap treeMap = new TreeMap(); treeMap.put("one", random.nextInt(10)); treeMap.put("two", random.nextInt(10)); treeMap.put("three", random.nextInt(10)); System.out.println("TreeMapDemo.testTreeMapOrdinaryAPIs-Begin"); // 打印TreeMap System.out.printf("打印treeMap:\n%s\n", treeMap);; // 通過Iterator遍歷key-value Iterator iterator = treeMap.entrySet().iterator(); System.out.println("通過Iterator遍歷key-value:"); while (iterator.hasNext()) { Map.Entry entity = (Map.Entry) iterator.next(); System.out.printf("%s-%s\n", entity.getKey(), entity.getValue()); } // TreeMap的鍵值對個數 System.out.printf("TreeMap的鍵值對個數:%s\n", treeMap.size()); // 是否包含key System.out.println("是否包含key:"); System.out.printf("是否包含key:one-%s\n", treeMap.containsKey("one")); System.out.printf("是否包含key:four-%s\n", treeMap.containsKey("four")); // 刪除key對應的鍵值對 System.out.println("刪除key對應的鍵值對:"); treeMap.remove("one"); System.out.printf("刪除key為one的鍵值對后,treeMap為:\n%s\n", treeMap); // 清空TreeMap的節點 System.out.println("清空treeMap的節點:"); treeMap.clear(); System.out.printf("%s\n", treeMap.isEmpty() ? "treeMap is empty!" : "treeMap is not empty!"); System.out.printf("%s\n", treeMap == null ? "treeMap is null!" : "treeMap is not null!"); System.out.println("TreeMapDemo.testTreeMapOrdinaryAPIs-End"); } /** * 測試TreeMap導航函數 */ private static void testNavigableMapAPIs() { // 創建TreeMap實例,TreeMap是 NavigableMap接口的實現類 NavigableMap navigableMap = new TreeMap(); navigableMap.put("aaa",1); navigableMap.put("bbb",2); navigableMap.put("ccc",3); navigableMap.put("ddd",4); System.out.println("TreeMapDemo.testNavigableMapAPIs-Begin"); // 打印TreeMap System.out.printf("打印navigableMap:\n%s\n", navigableMap); // 獲取第一個key和節點 System.out.printf("First key:%s\tFirst entry:%s\n", navigableMap.firstKey(), navigableMap.firstEntry()); // 獲取最后一個key和節點 System.out.printf("Last key:%s\tLast entry:%s\n", navigableMap.lastKey(), navigableMap.lastEntry()); // 獲取小於/等於 key為bbb 最大的key和節點 System.out.printf("Key floor before bbb:%s\t%s\n", navigableMap.floorKey("bbb"), navigableMap.floorEntry("bbb")); // 獲取小於 key為bbb 最大的key和節點 System.out.printf("Key lower before bbb:%s\t%s\n", navigableMap.lowerKey("bbb"), navigableMap.lowerEntry("bbb")); // 獲取大於/等於 key為bbb 最大的key和節點 System.out.printf("Key ceiling after bbb:%s\t%s\n", navigableMap.ceilingKey("bbb"), navigableMap.ceilingEntry("bbb")); // 獲取大於 key為bbb 最大的key和節點 System.out.printf("Key higher after bbb:%s\t%s\n", navigableMap.higherKey("bbb"), navigableMap.higherEntry("bbb")); System.out.println("TreeMapDemo.testNavigableMapAPIs-End"); } /** * 測試TreeMap的子Map函數 */ private static void testSubMapAPIs() { // 實例化TreeMap對象 TreeMap treeMap = new TreeMap(); treeMap.put("a",1); treeMap.put("b",2); treeMap.put("c",3); treeMap.put("d",4); System.out.println("TreeMapDemo.testSubMapAPIs-Begin"); // 打印TreeMap System.out.printf("打印TreeMap:\n%s\n", treeMap); // 打印 key為c節點 前的節點(默認不包含c節點) System.out.printf("打印 key為c節點 前的節點(默認不包含c節點):%s", treeMap.headMap("c")); System.out.printf("打印 key為c節點 前的節點(包含c節點):%s\n", treeMap.headMap("c", true)); System.out.printf("打印 key為c節點 前的節點(不包含c節點):%s\n", treeMap.headMap("c", false)); // 打印 key為c節點 后的節點(默認包含c節點) System.out.printf("打印 key為c節點 后的節點(默認包含c節點):%s\n", treeMap.tailMap("c")); System.out.printf("打印 key為c節點 后的節點(包含c節點)%s\n", treeMap.tailMap("c", true)); System.out.printf("打印 key為c節點 后的節點(不包含c節點)%s\n", treeMap.tailMap("c", false)); // 打印 key為a與c節點 之間的節點(默認不包含c節點) System.out.printf("打印 key為a與c節點 之間的節點(默認包含c節點):\n%s\n", treeMap.subMap("a", "c")); System.out.printf("打印 key為a與c節點 之間的節點(包含a、c節點):\n%s\n", treeMap.subMap("a", true, "c", true)); System.out.printf("打印 key為a與c節點 之間的節點(包含a節點):\n%s\n", treeMap.subMap("a", true, "c", false)); System.out.printf("打印 key為a與c節點 之間的節點(包含c節點):\n%s\n", treeMap.subMap("a", false, "c", true)); System.out.printf("打印 key為a與c節點 之間的節點(不包含a、c節點):\n%s\n", treeMap.subMap("a", false, "c", false)); // 正序打印TreeMap的key System.out.printf("正序打印TreeMap的key:\n%s\n", treeMap.navigableKeySet()); // 倒序打印TreeMap的key System.out.printf("倒序打印TreeMap的key:\n%s\n", treeMap.descendingKeySet()); System.out.println("TreeMapDemo.testSubMapAPIs-End"); } }

TreeMapDemo.testTreeMapOrdinaryAPIs-Begin 打印treeMap: {one=2, three=5, two=1} 通過Iterator遍歷key-value: one-2 three-5 two-1 TreeMap的鍵值對個數:3 是否包含key: 是否包含key:one-true 是否包含key:four-false 刪除key對應的鍵值對: 刪除key為one的鍵值對后,treeMap為: {three=5, two=1} 清空treeMap的節點: treeMap is empty! treeMap is not null! TreeMapDemo.testTreeMapOrdinaryAPIs-End TreeMapDemo.testNavigableMapAPIs-Begin 打印navigableMap: {aaa=1, bbb=2, ccc=3, ddd=4} First key:aaa First entry:aaa=1 Last key:ddd Last entry:ddd=4 Key floor before bbb:bbb bbb=2 Key lower before bbb:aaa aaa=1 Key ceiling after bbb:bbb bbb=2 Key higher after bbb:ccc ccc=3 TreeMapDemo.testNavigableMapAPIs-End TreeMapDemo.testSubMapAPIs-Begin 打印TreeMap: {a=1, b=2, c=3, d=4} 打印 key為c節點 前的節點(默認不包含c節點):{a=1, b=2}打印 key為c節點 前的節點(包含c節點):{a=1, b=2, c=3} 打印 key為c節點 前的節點(不包含c節點):{a=1, b=2} 打印 key為c節點 后的節點(默認包含c節點):{c=3, d=4} 打印 key為c節點 后的節點(包含c節點){c=3, d=4} 打印 key為c節點 后的節點(不包含c節點){d=4} 打印 key為a與c節點 之間的節點(默認包含c節點): {a=1, b=2} 打印 key為a與c節點 之間的節點(包含a、c節點): {a=1, b=2, c=3} 打印 key為a與c節點 之間的節點(包含a節點): {a=1, b=2} 打印 key為a與c節點 之間的節點(包含c節點): {b=2, c=3} 打印 key為a與c節點 之間的節點(不包含a、c節點): {b=2} 正序打印TreeMap的key: [a, b, c, d] 倒序打印TreeMap的key: [d, c, b, a] TreeMapDemo.testSubMapAPIs-End
2.TreeMap遍歷使用Demo:

import org.springframework.util.StringUtils; import java.util.*; /** * @author nana * @date 2019/2/23 */ public class TreeMapIteratorTest { public static void main(String[] args) { // 創建treeMap對象 TreeMap treeMap = treeMapTest(); // 通過entrySet()遍歷TreeMap的節點 iteratorTreeMapByEntrySet(treeMap); // 通過keySet()遍歷TreeMap的節點 iteratorTreeMapByKeySet(treeMap); // 遍歷TreeMap的value iteratorTreeMapByValue(treeMap); } /** * 創建treeMap對象 * @return */ private static TreeMap treeMapTest() { String key = null; int keyValue = 0; Integer value = null; Random random = new Random(); TreeMap treeMap = new TreeMap(); int i = 0; while (i < 6) { // 隨機獲取[0,50)的整數 keyValue = random.nextInt(50); key = String.valueOf(keyValue); value = random.nextInt(10); // 添加到treeMap中 treeMap.put(key, value); i++; } return treeMap; } /** * 通過entrySet()遍歷TreeMap的節點 */ private static void iteratorTreeMapByEntrySet(TreeMap treeMapTest) { if (StringUtils.isEmpty(treeMapTest)) { return; } // 遍歷TreeMap Iterator iterator = treeMapTest.entrySet().iterator(); System.out.println("通過entrySet()遍歷TreeMap的節點:"); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); System.out.printf("%s-%s\t", entry.getKey(), entry.getValue()); } } /** * 通過keySet()遍歷TreeMap的節點 */ private static void iteratorTreeMapByKeySet(TreeMap treeMapTest) { if(StringUtils.isEmpty(treeMapTest)) { return; } String key = null; Integer value = null; Iterator iterator = treeMapTest.keySet().iterator(); System.out.println("\n通過keySet()遍歷TreeMap的節點:"); while (iterator.hasNext()) { key = (String) iterator.next(); value = (Integer) treeMapTest.get(key); System.out.printf("%s-%s\t", key, value); } } /** * 遍歷TreeMap的value */ private static void iteratorTreeMapByValue(TreeMap treeMapTest) { if (treeMapTest == null) { return; } Collection collection = treeMapTest.values(); Iterator iterator = collection.iterator(); System.out.println("\n遍歷TreeMap的value:"); while (iterator.hasNext()) { System.out.printf("%s\t", iterator.next()); } } }

通過entrySet()遍歷TreeMap的節點: 19-0 2-7 20-1 22-0 34-3 通過keySet()遍歷TreeMap的節點: 19-0 2-7 20-1 22-0 34-3 遍歷TreeMap的value: 0 7 1 0 3