Guava集合--新集合型別
Guava引入了很多JDK沒有的、但我們發現明顯有用的新集合型別。這些新型別是為了和JDK集合框架共存,而沒有往JDK集合抽象中硬塞其他概念。作為一般規則,Guava集合非常精準地遵循了JDK介面契約。
一.Multiset
1.統計一個詞在檔案中出現了多少次,傳統的做法是這樣的:
Map<String, Integer> counts = new HashMap<String, Integer>(); for (String word : words) { Integer count = counts.get(word); if (count == null) { counts.put(word, 1); } else { counts.put(word, count + 1); } }
這種寫法很笨拙,也容易出錯,並且不支援同時收集多種統計資訊,如總詞數。我們可以做的更好。
2.Guava提供了多種Multiset的實現,大致對應JDK中Map的各種實現:
Map | 對應的Multiset | 是否支援null元素 |
HashMap | HashMultiset | 是 |
TreeMap | TreeMultiset | 是(如果comparator支援的話) |
LinkedHashMap | LinkedHashMultiset | 是 |
ConcurrentHashMap | ConcurrentHashMultiset | 否 |
ImmutableMap | ImmutableMultiset |
否 |
3.Multiset的方法如下
方法 | 描述 |
count(E) | 給定元素在Multiset中的計數 |
elementSet() | Multiset中不重複元素的集合,型別為Set<E> |
entrySet() | 和Map的entrySet類似,返回Set<Multiset.Entry<E>>,其中包含的Entry支援getElement()和getCount()方法 |
add(E, int) | 增加給定元素在Multiset中的計數 |
remove(E, int) | 減少給定元素在Multiset中的計數 |
setCount(E, int) |
設定給定元素在Multiset中的計數,不可以為負數 |
size() | 返回集合元素的總個數(包括重複的元素) |
package collections; import com.google.common.collect.HashMultiset;
import com.google.common.collect.Lists;
import com.google.common.collect.Multiset; import java.util.Set; public class GuavaMultiset {
public static void main(String[] args) {
Multiset<String> multiset = HashMultiset.create();
multiset.addAll( Lists.newArrayList("I","love","China","China","is","my","love")); int love = multiset.count("love");
System.out.println("love num:" + love); Set<String> elementSet = multiset.elementSet();
System.out.println("Multiset中不重複元素的集合,型別為Set<E>:" + elementSet); Set<Multiset.Entry<String>> entries = multiset.entrySet();//統計元素頻次
System.out.println("entrySet:" + entries);//[love x 2, China x 2, I, is, my] multiset.add("add",2);
System.out.println("增加add後的資料:" + multiset); multiset.remove("add",2);
System.out.println("移除add後的資料:" + multiset); multiset.setCount("love", 1);
System.out.println("設定love計數為1後的資料:" + multiset); System.out.println("返回集合中的總個數:" + multiset.size());
}
}
執行結果:
可以用兩種方式看待Multiset:
- 沒有元素順序限制的ArrayList<E>
- Map<E, Integer>,鍵為元素,值為計數
Guava的Multiset API也結合考慮了這兩種方式:
當把Multiset看成普通的Collection時,它表現得就像無序的ArrayList:
- add(E)新增單個給定元素
- iterator()返回一個迭代器,包含Multiset的所有元素(包括重複的元素)
- size()返回所有元素的總個數(包括重複的元素)
當把Multiset看作Map<E, Integer>時,它也提供了符合效能期望的查詢操作:
- count(Object)返回給定元素的計數。HashMultiset.count的複雜度為O(1),TreeMultiset.count的複雜度為O(log n)。
- entrySet()返回Set<Multiset.Entry<E>>,和Map的entrySet類似。
- elementSet()返回所有不重複元素的Set<E>,和Map的keySet()類似。
- 所有Multiset實現的記憶體消耗隨著不重複元素的個數線性增長。
值得注意的是,除了極少數情況,Multiset和JDK中原有的Collection介面契約完全一致——具體來說,TreeMultiset在判斷元素是否相等時,與TreeSet一樣用compare,而不是Object.equals。另外特別注意,Multiset.addAll(Collection)可以新增Collection中的所有元素並進行計數,這比用for迴圈往Map新增元素和計數方便多了。
二.Multimap
1.傳統實現
每個有經驗的Java程式設計師都在某處實現過Map<K, List<V>>或Map<K, Set<V>>,並且要忍受這個結構的笨拙,以便做相應的業務邏輯處理。例如:
Map<String, List<Student>> studentMap = new HashMap<>();
for (int i = 0; i < 5; i++) {
Student student = new Student();
student.setName("multimap"+i);
student.setAge(i);
List<Student> list = studentMap.get(student.getName());
if (list != null) {
list.add(student);
} else {
list = new ArrayList<>();
list.add(student);
studentMap.put(student.getName(), list);
} }
像 Map<String, List<StudentScore>> StudentScoreMap =newHashMap<String, List<StudentScore>>()這樣的資料結構,自己實現起來太麻煩,你需要檢查key是否存在,不存在時則建立一個,存在時在List後面新增上一個。這個過程是比較痛苦的,如果你希望檢查List中的物件是否存在,刪除一個物件,或者遍歷整個資料結構,那麼則需要更多的程式碼來實現。
2.關於Multimap
Guava的Multimap就提供了一個方便地把一個鍵對應到多個值的資料結構。讓我們可以簡單優雅的實現上面複雜的資料結構,讓我們的精力和時間放在實現業務邏輯上,而不是在資料結構上,下面我們具體來看看Multimap的相關知識點。
可以用兩種方式思考Multimap的概念:”鍵-單個值對映”的集合:
a -> 1 a -> 2 a ->4 b -> 3 c -> 5
或者”鍵-值集合對映”的對映:
a -> [1, 2, 4] b -> 3 c -> 5
一般來說,Multimap介面應該用第一種方式看待,但asMap()檢視返回Map<K, Collection<V>>,讓你可以按另一種方式看待Multimap。重要的是,不會有任何鍵對映到空集合:一個鍵要麼至少到一個值,要麼根本就不在Multimap中。
很少會直接使用Multimap介面,更多時候你會用ListMultimap或SetMultimap介面,它們分別把鍵對映到List或Set。
3.Multimap的方法有:
方法簽名 | 描述 | 等價於 |
put(K, V) | 新增鍵到單個值的對映 | multimap.get(key).add(value) |
putAll(K, Iterable<V>) | 依次新增鍵到多個值的對映 | Iterables.addAll(multimap.get(key), values) |
remove(K, V) | 移除鍵到值的對映;如果有這樣的鍵值併成功移除,返回true。 | multimap.get(key).remove(value) |
removeAll(K) | 清除鍵對應的所有值,返回的集合包含所有之前對映到K的值,但修改這個集合就不會影響Multimap了。 | multimap.get(key).clear() |
replaceValues(K, Iterable<V>) | 清除鍵對應的所有值,並重新把key關聯到Iterable中的每個元素。返回的集合包含所有之前對映到K的值。 | multimap.get(key).clear(); Iterables.addAll(multimap.get(key), values) |
例子:
package collections; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap; import java.util.ArrayList;
import java.util.List; public class GuavaMultimap {
public static void main(String[] args) {
Multimap<String,Student> stuMultimap = ArrayListMultimap.create();
Student student1 = new Student();
student1.setName("student1");
student1.setAge(1);
stuMultimap.put("student",student1);
stuMultimap.put("student1",student1);
System.out.println("-------------put(K, V),新增鍵到單個值的對映---------------");
System.out.println(stuMultimap); Student student2 = new Student();
student2.setName("student2");
student2.setAge(2);
Student student3 = new Student();
student3.setName("student3");
student3.setAge(3);
List<Student> stuList = new ArrayList<>();
stuList.add(student2);
stuList.add(student3);
stuMultimap.putAll("student2and3",stuList);
System.out.println("-------------putAll(K, Iterable<V>),依次新增鍵到多個值的對映---------------");
System.out.println(stuMultimap); stuMultimap.remove("student",student1);
System.out.println("-------------remove(K, V),移除鍵到值的對映;如果有這樣的鍵值併成功移除,返回true。---------------");
System.out.println(stuMultimap); stuMultimap.removeAll("student2and3");
System.out.println("-------------removeAll(K),清除鍵對應的所有值,返回的集合包含所有之前對映到K的值,但修改這個集合就不會影響Multimap了。---------------");
System.out.println(stuMultimap); stuMultimap.replaceValues("student1",stuList);
System.out.println("-------------replaceValues(K, Iterable<V>),清除鍵對應的所有值,並重新把key關聯到Iterable中的每個元素。返回的集合包含所有之前對映到K的值。---------------");
System.out.println(stuMultimap);
}
}
執行結果:
4.Multimap的各種實現
Multimap提供了多種形式的實現。在大多數要使用Map<K, Collection<V>>的地方,你都可以使用它們:
實現 | 鍵行為類似 | 值行為類似 |
ArrayListMultimap | HashMap | ArrayList |
HashMultimap | HashMap | HashSet |
LinkedListMultimap* | LinkedHashMap* | LinkedList* |
LinkedHashMultimap** | LinkedHashMap | LinkedHashMap |
TreeMultimap | TreeMap | TreeSet |
ImmutableListMultimap | ImmutableMap | ImmutableList |
ImmutableSetMultimap | ImmutableMap | ImmutableSet |
以上這些實現,除了immutable的實現都支援null的鍵和值。
*LinkedListMultimap.entries()保留了所有鍵和值的迭代順序。
**LinkedHashMultimap保留了對映項的插入順序,包括鍵插入的順序,以及鍵對映的所有值的插入順序。
請注意,並非所有的Multimap都和上面列出的一樣,使用Map<K, Collection<V>>來實現(特別是,一些Multimap實現用了自定義的hashTable,以最小化開銷)
如果你想要更大的定製化,請用Multimaps.newMultimap(Map, Supplier<Collection>)或list和set版本,使用自定義的Collection、List或Set實現Multimap。
5.Multimap也支援一系列強大的檢視功能:
1.asMap把自身Multimap<K, V>對映成Map<K, Collection<V>>檢視。這個Map檢視支援remove和修改操作,但是不支援put和putAll。嚴格地來講,當你希望傳入引數是不存在的key,而且你希望返回的是null而不是一個空的可修改的集合的時候就可以呼叫 asMap().get(key)。(你可以強制轉型asMap().get(key)的結果型別-對SetMultimap的結果轉成Set,對ListMultimap的結果轉成List型-但是直接把ListMultimap轉成Map<K, List<V>>是不行的。)
2.entries檢視是把Multimap裡所有的鍵值對以Collection<Map.Entry<K, V>>的形式展現。
3.keySet檢視是把Multimap的鍵集合作為檢視
4.keys檢視返回的是個Multiset,這個Multiset是以不重複的鍵對應的個數作為檢視。這個Multiset可以通過支援移除操作而不是新增操作來修改Multimap。
5.values()檢視能把Multimap裡的所有值“平展”成一個Collection<V>。這個操作和Iterables.concat(multimap.asMap().values())很相似,只是它返回的是一個完整的Collection。
儘管Multimap的實現用到了Map,但Multimap<K, V>不是Map<K, Collection<V>>。因為兩者有明顯區別:
1.Multimap.get(key)一定返回一個非null的集合。但這不表示Multimap使用了記憶體來關聯這些鍵,相反,返回的集合只是個允許新增元素的檢視。
2.如果你喜歡像Map那樣當不存在鍵的時候要返回null,而不是Multimap那樣返回空集合的話,可以用asMap()返回的檢視來得到Map<K, Collection<V>>。(這種情況下,你得把返回的Collection<V>強轉型為List或Set)。
3.Multimap.containsKey(key)只有在這個鍵存在的時候才返回true。
4.Multimap.entries()返回的是Multimap所有的鍵值對。但是如果需要key-collection的鍵值對,那就得用asMap().entries()。
5.Multimap.size()返回的是entries的數量,而不是不重複鍵的數量。如果要得到不重複鍵的數目就得用Multimap.keySet().size()。
例子:
package collections; import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multiset; import java.util.Collection;
import java.util.Map;
import java.util.Set; public class GuavaMultimap {
public static void main(String[] args) {
Multimap<String,Student> stuMultimap = ArrayListMultimap.create();
Student student1 = new Student();
student1.setName("student1");
student1.setAge(1);
Student student2 = new Student();
student2.setName("student2");
student2.setAge(2);
Student student3 = new Student();
student3.setName("student3");
student3.setAge(3);
stuMultimap.put("student1",student1);
stuMultimap.put("student2and3",student2);
stuMultimap.put("student2and3",student3); Map<String, Collection<Student>> stringCollectionMap = stuMultimap.asMap();
System.out.println("-------------asMap把自身Multimap<K, V>對映成Map<K, Collection<V>>檢視。---------------");
System.out.println(stringCollectionMap); Collection<Map.Entry<String, Student>> entries = stuMultimap.entries();
System.out.println("-------------entries檢視是把Multimap裡所有的鍵值對以Collection<Map.Entry<K, V>>的形式展現。---------------");
System.out.println(entries); Set<String> strings = stuMultimap.keySet();
System.out.println("-------------keySet檢視是把Multimap的鍵集合作為檢視---------------");
System.out.println(strings); Multiset<String> keys = stuMultimap.keys();
System.out.println("-------------keys檢視返回的是個Multiset,這個Multiset是以不重複的鍵對應的個數作為檢視。這個Multiset可以通過支援移除操作而不是新增操作來修改Multimap。---------------");
System.out.println(keys); Collection<Student> values = stuMultimap.values();
System.out.println("-------------values()檢視能把Multimap裡的所有值“平展”成一個Collection<V>。---------------");
System.out.println(values); Collection<Student> stus = stuMultimap.get("student1");
System.out.println("-------------Multimap.get(key)一定返回一個非null的集合。---------------");
System.out.println(stus); boolean student1Key = stuMultimap.containsKey("student1");
System.out.println("-------------Multimap.containsKey(key)只有在這個鍵存在的時候才返回true。---------------");
System.out.println(student1Key); int size = stuMultimap.size();
System.out.println("-------------Multimap.size()返回的是entries的數量,而不是不重複鍵的數量。---------------");
System.out.println(size);
}
}
執行結果:
三.BiMap
相信有很多開發者會遇到這種情況:在開發的過程中,定義了一個Map,往往是通過key來查詢value的,但如果需要通過value來查詢key,我們就需要額外編寫一些程式碼了。
剛好BiMap提供了一種新的集合型別,它提供了key和value的雙向關聯的資料結構。下面我們來看看這兩者的實現:
1.傳統的做法:
package com.guava; import java.util.Map;
import java.util.Map.Entry; import com.google.common.collect.Maps; public class BiMapTest { public static void main(String[] args) {
Map<Integer,String> idToName = Maps.newHashMap();
idToName.put(1,"zhangsan");
idToName.put(2,"lisi");
idToName.put(3,"wangwu"); System.out.println("idToName:"+idToName); Map<String,Integer> nameToId = Maps.newHashMap();
for(Entry<Integer, String> entry: idToName.entrySet()) {
nameToId.put(entry.getValue(), entry.getKey());
}
System.out.println("nameToId:"+nameToId);
} }
執行結果:
上面的程式碼可以幫助我們實現map倒轉的要求,但是還有一些我們需要考慮的問題:
1. 如何處理重複的value的情況。不考慮的話,反轉的時候就會出現覆蓋的情況.
2. 如果在反轉的map中增加一個新的key,倒轉前的map是否需要更新一個值呢?
在這種情況下需要考慮的業務以外的內容就增加了,編寫的程式碼也變得不那麼易讀了。這時我們就可以考慮使用Guava中的BiMap了。
2.使用Guava中的BiMap
package com.guava; import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap; public class BiMapTest { public static void main(String[] args) {
BiMap<Integer,String> idToName = HashBiMap.create();
idToName.put(1,"zhangsan");
idToName.put(2,"lisi");
idToName.put(3,"wangwu"); System.out.println("idToName:"+idToName); BiMap<String,Integer> nameToId = idToName.inverse(); System.out.println("nameToId:"+nameToId);
} }
執行結果:
3.關於Bimap資料的強制唯一性
在使用BiMap進行key、value反轉時,會要求Value的唯一性。如果value重複了則會丟擲錯誤:java.lang.IllegalArgumentException,例如:
package com.guava; import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap; public class BiMapTest { public static void main(String[] args) {
BiMap<Integer,String> idToName = HashBiMap.create();
idToName.put(1,"zhangsan");
idToName.put(2,"lisi");
idToName.put(3,"wangwu");
idToName.put(4, "wangwu"); System.out.println("idToName:"+idToName); BiMap<String,Integer> nameToId = idToName.inverse(); System.out.println("nameToId:"+nameToId);
} }
執行結果:
如果我們確實需要插入重複的value值,那可以選擇forcePut方法。但是我們需要注意的是前面的key也會被覆蓋了。
package com.guava; import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap; public class BiMapTest { public static void main(String[] args) {
BiMap<Integer,String> idToName = HashBiMap.create();
idToName.put(1,"zhangsan");
idToName.put(2,"lisi");
idToName.put(3,"wangwu");
idToName.forcePut(4, "wangwu"); System.out.println("idToName:"+idToName); BiMap<String,Integer> nameToId = idToName.inverse(); System.out.println("nameToId:"+nameToId);
} }
執行結果:
4.BiMap的各種實現
鍵–值實現 | 值–鍵實現 | 對應的BiMap實現 |
HashMap | HashMap | HashBiMap |
ImmutableMap | ImmutableMap | ImmutableBiMap |
EnumMap | EnumMap | EnumBiMap |
EnumMap | HashMap | EnumHashBiMap |
四.Table
當我們需要多個索引的資料結構的時候,通常情況下,我們只能用這種醜陋的Map<FirstName, Map<LastName, Person>>來實現。為此Guava提供了一個新的集合型別-Table集合型別,來支援這種資料結構的使用場景。Table支援“row”和“column”,而且提供多種檢視。
1.例子
package com.guava; import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table; public class TableTest { public static void main(String[] args) {
Table<String, Integer, String> aTable = HashBasedTable.create(); aTable.put("A", 1, "A1");
aTable.put("A", 2, "A2");
aTable.put("B", 2, "B2"); System.out.println(aTable.column(2));
System.out.println(aTable.row("B"));
System.out.println(aTable.get("B", 2)); System.out.println(aTable.contains("B", 2));
System.out.println(aTable.containsColumn(2));
System.out.println(aTable.containsRow("B"));
System.out.println(aTable.columnMap());
System.out.println(aTable.rowMap()); System.out.println(aTable.remove("B", 2));
} }
執行結果:
2.Table的檢視
rowMap():用Map<R, Map<C, V>>表現Table<R, C, V>。同樣的,rowKeySet()返回”行”的集合Set<R>。
row(r):用Map<C, V>返回給定”行”的所有列,對這個map進行的寫操作也將寫入Table中。
類似的列訪問方法:columnMap()、columnKeySet()、column(c)。(基於列的訪問會比基於的行訪問稍微低效點)
cellSet():用元素型別為Table.Cell<R, C, V>的Set表現Table<R, C, V>。Cell類似於Map.Entry,但它是用行和列兩個鍵區分的。
3.Table有如下幾種實現:
HashBasedTable:本質上用HashMap<R, HashMap<C, V>>實現;
TreeBasedTable:本質上用TreeMap<R, TreeMap<C,V>>實現;
ImmutableTable:本質上用ImmutableMap<R, ImmutableMap<C, V>>實現;注:ImmutableTable對稀疏或密集的資料集都有優化。
ArrayTable:要求在構造時就指定行和列的大小,本質上由一個二維陣列實現,以提升訪問速度和密集Table的記憶體利用率。ArrayTable與其他Table的工作原理有點不同。
五.ClassToInstanceMap
ClassToInstanceMap是一種特殊的Map:它的鍵是型別,而值是符合鍵所指型別的物件。
為了擴充套件Map介面,ClassToInstanceMap額外宣告瞭兩個方法:T getInstance(Class<T>)和T putInstance(Class<T>, T),從而避免強制型別轉換,同時保證了型別安全。
ClassToInstanceMap有唯一的泛型引數,通常稱為B,代表Map支援的所有型別的上界。例如:
ClassToInstanceMap<Number> numberDefaults = MutableClassToInstanceMap.create();
numberDefaults.putInstance(Integer.class, Integer.valueOf(0));
從技術上講,ClassToInstanceMap<B>實現了Map<Class<? extends B>, B>——或者換句話說,是一個對映B的子型別到對應例項的Map。這讓ClassToInstanceMap包含的泛型宣告有點令人困惑,但請記住B始終是Map所支援型別的上界——通常B就是Object。
對於ClassToInstanceMap,Guava提供了兩種有用的實現:MutableClassToInstanceMap和ImmutableClassToInstanceMap。
例子:
package com.guava; import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.MutableClassToInstanceMap; public class ClassToInstanceMapTest { public static void main(String[] args) {
ClassToInstanceMap<Object> classToInstanceMapString =MutableClassToInstanceMap.create();
classToInstanceMapString.put(String.class, "lisi");
classToInstanceMapString.put(Integer.class, 666);
System.out.println("string:"+classToInstanceMapString.getInstance(String.class));
System.out.println("Integer:"+classToInstanceMapString.getInstance(Integer.class));
} }
執行結果:
六.RangeSet
RangeSet類是用來儲存一些不為空的也不相交的範圍的資料結構。假如需要向RangeSet的物件中加入一個新的範圍,那麼任何相交的部分都會被合併起來,所有的空範圍都會被忽略。
講了這麼多,我們該怎麼樣利用RangeSet?RangeSet類是一個介面,需要用它的子類來宣告一個RangeSet型的物件,實現了RangeSet介面的類有ImmutableRangeSet和TreeRangeSet,ImmutableRangeSet是一個不可修改的RangeSet,而TreeRangeSet是利用樹的形式來實現。下面主要談TreeRangeSet的用法:
package com.guava; import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;
import com.google.common.collect.TreeRangeSet; public class RangeSetTest { public static void main(String[] args) {
RangeSet<Integer> rangeSet = TreeRangeSet.create();
rangeSet.add(Range.closed(1, 10));
System.out.println("rangeSet:"+rangeSet);
rangeSet.add(Range.closedOpen(11, 15));
System.out.println("rangeSet:"+rangeSet);
rangeSet.add(Range.open(15, 20));
System.out.println("rangeSet:"+rangeSet);
rangeSet.add(Range.openClosed(0, 0));
System.out.println("rangeSet:"+rangeSet);
rangeSet.remove(Range.open(5, 10));
System.out.println("rangeSet:"+rangeSet);
} }
執行結果:
請注意,要合併Range.closed(1, 10)和Range.closedOpen(11, 15)這樣的區間,你需要首先用Range.canonical(DiscreteDomain)對區間進行預處理,例如DiscreteDomain.integers()。
注:RangeSet不支援GWT,也不支援JDK5和更早版本;因為,RangeSet需要充分利用JDK6中NavigableMap的特性。
1.RangeSet的檢視
RangeSet的實現支援非常廣泛的檢視:
- complement():返回RangeSet的補集檢視。complement也是RangeSet型別,包含了不相連的、非空的區間。
- subRangeSet(Range<C>):返回RangeSet與給定Range的交集檢視。這擴充套件了傳統排序集合中的headSet、subSet和tailSet操作。
- asRanges():用Set<Range<C>>表現RangeSet,這樣可以遍歷其中的Range。
- asSet(DiscreteDomain<C>)(僅ImmutableRangeSet支援):用ImmutableSortedSet<C>表現RangeSet,以區間中所有元素的形式而不是區間本身的形式檢視。(這個操作不支援DiscreteDomain和RangeSet都沒有上邊界,或都沒有下邊界的情況)
2.RangeSet的查詢方法
為了方便操作,RangeSet直接提供了若干查詢方法,其中最突出的有:
- contains(C):RangeSet最基本的操作,判斷RangeSet中是否有任何區間包含給定元素。
- rangeContaining(C):返回包含給定元素的區間;若沒有這樣的區間,則返回null。
- encloses(Range<C>):簡單明瞭,判斷RangeSet中是否有任何區間包括給定區間。
- span():返回包括RangeSet中所有區間的最小區間。
七.RangeMap
RangeMap描述了”不相交的、非空的區間”到特定值的對映。和RangeSet不同,RangeMap不會合並相鄰的對映,即便相鄰的區間對映到相同的值。
1.RangeMap的檢視
RangeMap提供兩個檢視:
- asMapOfRanges():用Map<Range<K>, V>表現RangeMap。這可以用來遍歷RangeMap。
- subRangeMap(Range<K>):用RangeMap型別返回RangeMap與給定Range的交集檢視。這擴充套件了傳統的headMap、subMap和tailMap操作。
例子:
package com.guava; import com.google.common.collect.Range;
import com.google.common.collect.RangeMap;
import com.google.common.collect.TreeRangeMap; public class RangeMapTest { public static void main(String[] args) {
RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
rangeMap.put(Range.closed(1, 10), "foo");
System.out.println("rangeMap:"+rangeMap);
rangeMap.put(Range.open(3, 6), "bar");
System.out.println("rangeMap:"+rangeMap);
rangeMap.put(Range.open(10, 20), "foo");
System.out.println("rangeMap:"+rangeMap);
rangeMap.remove(Range.closed(5, 11));
System.out.println("rangeMap:"+rangeMap); RangeMap<Integer, String> subRangeMap = rangeMap.subRangeMap(Range.closed(3, 15));
System.out.println("subRangeMap:"+subRangeMap);
} }
執行結果: