如果你需要在不可變集合中使用 null,請使用 JDK 中的 Collections.unmodifiableXXX 方法
-
ImmutableSet
http://wiki.jikexueyuan.com/project/google-guava-official-tutorial/immutable-collections.html
https://www.yiibai.com/guava/guava_collections_utilities.html
package com.byedbl.common.collect;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.junit.Test;
import java.util.Collections;
import java.util.Set;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
public class ImmutableSetTest {
@Test
public void testCreation_oneDuplicate() {
// now we'll get the varargs overload
ImmutableSet<String> set =
ImmutableSet.of("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "a");
assertEquals(
Lists.newArrayList("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"),
Lists.newArrayList(set));
}
@Test
public void testCreation_manyDuplicates() {
// now we'll get the varargs overload
ImmutableSet<String> set =
ImmutableSet.of("a", "b", "c", "c", "c", "c", "b", "b", "a", "a", "c", "c", "c", "a");
assertThat(set).containsExactly("a", "b", "c").inOrder();
}
@Test
public void testCreation_arrayOfArray() {
String[] array = new String[] {"a","b","b"};
Set<String[]> set = ImmutableSet.<String[]>of(array);
assertEquals(Collections.singleton(array), set);
}
@Test
public void testCreation_Builder() {
Set<String> set = ImmutableSet.<String>builder().add("a").add("b").build();
assertEquals(Sets.newHashSet("a","b"),set);
}
@Test
public void testCreation_SortedSet() {
ImmutableSortedSet<String> set = ImmutableSortedSet.of("a", "b", "c", "a", "d", "b");
set.asList().forEach(System.out::println);
}
}
Multiset
繼承自Collection
而非 Set
接口,所以其可以包含重復(fù)元素
可以用兩種方式看待 Multiset:
- 沒有元素順序限制的 ArrayList
- Map<E, Integer>,鍵為元素,值為計數(shù)
package com.byedbl.common.collect;
import com.google.common.collect.Multiset;
import com.google.common.collect.Sets;
import com.google.common.collect.TreeMultiset;
import org.junit.Test;
import java.util.Arrays;
import java.util.Set;
import static org.junit.Assert.assertEquals;
public class MultisetsTest {
// @Test
// public void testNewTreeMultisetDerived() {
// TreeMultiset<DerivedComparable> set = TreeMultiset.create();
// assertTrue(set.isEmpty());
// set.add(new DerivedComparable("foo"), 2);
// set.add(new DerivedComparable("bar"), 3);
// assertThat(set)
// .containsExactly(
// new DerivedComparable("bar"),
// new DerivedComparable("bar"),
// new DerivedComparable("bar"),
// new DerivedComparable("foo"),
// new DerivedComparable("foo"))
// .inOrder();
// }
/**
* 初始化Set值
* @return :
*/
private TreeMultiset<String> getSet() {
TreeMultiset<String> set = TreeMultiset.create();
set.add("foo", 2);
set.add("bar", 3);
set.addAll(Arrays.asList("a", "a", "b", "b"));
return set;
}
@Test
public void testTreeMultiSetSize() {
TreeMultiset<String> set = getSet();
// 統(tǒng)計Set中總個數(shù)9個,包含重復(fù)的個數(shù)
assertEquals(9,set.size());
}
@Test
public void testTreeMultiSetCount() {
TreeMultiset<String> set = getSet();
//取出指定元素的個數(shù)
assertEquals(2,set.count("foo"));
}
@Test
public void testTreeMultiSetElementSet() {
Set<String> treeSet = Sets.newTreeSet();
treeSet.addAll(Arrays.asList("a", "bar", "foo","b"));
TreeMultiset<String> set = getSet();
// set.elementSet().forEach(System.out::println);
//返回不重復(fù)的兩個元素
assertEquals(treeSet,set.elementSet());
}
@Test
public void testTreeMultiSetElementSetSize() {
TreeMultiset<String> set = getSet();
//不重復(fù)元素的個數(shù)
assertEquals(4,set.elementSet().size());
}
@Test
public void testTreeMultiSetEntrySet() {
TreeMultiset<String> set = getSet();
Set<Multiset.Entry<String>> entries = set.entrySet();
//遍歷取出集合中的元素
entries.forEach(entry-> System.out.println(entry.getElement()+" : "+ entry.getCount()));
}
@Test
public void testTreeMultiSetAdd() {
//增加給定元素在 Multiset 中的計數(shù)
TreeMultiset<String> set = getSet();
set.add("foo", 3);
assertEquals(5,set.count("foo"));
}
@Test
public void testTreeMultiSetRemove() {
TreeMultiset<String> set = getSet();
set.remove("foo", 1);
assertEquals(1,set.count("foo"));
}
@Test
public void testTreeMultiSetSetCount() {
TreeMultiset<String> set = getSet();
set.setCount("foo", 5);
assertEquals(5,set.count("foo"));
}
}
Map<K, List>或 Map<K, Set>
Multimap 是把鍵映射到任意多個值的一般方式
ListMultimap.get(key)返回 List,SetMultimap.get(key)返回 Set。
*LinkedListMultimap.entries()保留了所有鍵和值的迭代順序。詳情見 doc 鏈接。
**LinkedHashMultimap 保留了映射項的插入順序,包括鍵插入的順序,以及鍵映射的所有值的插入順序。
package com.byedbl.common.collect;
import com.google.common.collect.*;
import org.junit.Test;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import static org.junit.Assert.*;
public class MultimapTest {
private Multimap<String, String> getMultimap() {
Multimap<String,String> multimap = HashMultimap.create();
multimap.putAll("foo", Sets.newHashSet("foo1", "foo2"));
multimap.putAll("bar", Sets.newHashSet("bar1", "bar2"));
multimap.put("test", "a");
multimap.put("test", "b");
return multimap;
}
@Test
public void testMultimap() {
Multimap<String, String> multimap = getMultimap();
//遍歷打印結(jié)果
// test : [a, b]
// foo : [foo2, foo1]
// bar : [bar1, bar2]
printMap(multimap);
}
private void printMap(Multimap<String, String> multimap) {
multimap.asMap().forEach((k,v)-> System.out.println(k + " : "+ v));
}
@Test
public void testMultimapSize() {
Multimap<String, String> multimap = getMultimap();
assertEquals(6, multimap.size());
//Set<K>
assertEquals(3,multimap.keySet().size());
//Multiset<K>
assertEquals(6,multimap.keys().size());
//Collection<V>
assertEquals(6,multimap.values().size());
//Collection<Entry<K, V>>
assertEquals(6,multimap.entries().size());
//Map<K, Collection<V>>
assertEquals(3,multimap.asMap().size());
}
@Test
public void testMultimapRemove(){
Multimap<String, String> multimap = getMultimap();
//刪除指定元素
assertTrue(multimap.get("foo").remove("foo2"));
assertTrue(multimap.remove("test","a"));
printMap(multimap);
}
@Test
public void testMultimapRemoveAll() {
Multimap<String, String> multimap = getMultimap();
//清除鍵對應(yīng)的所有值,返回的集合包含所有之前映射到 K 的值,
// 但修改這個集合就不會影響 Multimap 了。
//multimap.get(key).clear()
assertArrayEquals(multimap.removeAll("foo").toArray(),new String[]{"foo2","foo1"});
}
@Test
public void testMultimapReplaceValues() {
Multimap<String, String> multimap = getMultimap();
//清除鍵對應(yīng)的所有值,并重新把 key 關(guān)聯(lián)到 Iterable 中的每個元素。
// 返回的集合包含所有之前映射到 K 的值。
multimap.replaceValues("foo", Lists.newArrayList("foo3", "foo4"));
assertArrayEquals(multimap.get("foo").toArray(),new String[]{"foo3", "foo4"});
printMap(multimap);
}
@Test
public void testMultimapEntries() {
Multimap<String, String> multimap = getMultimap();
Collection<Map.Entry<String, String>> entries = multimap.entries();
//遍歷key和values值
entries.forEach(entry-> System.out.println(entry.getKey()+" : " + entry.getValue()));
}
@Test
public void testMultimapKeySet() {
Multimap<String, String> multimap = getMultimap();
Set<String> set = multimap.keySet();
assertEquals(set,Sets.newHashSet("test","bar","foo"));
set.forEach(System.out::println);
}
@Test
public void testMultimapValues() {
Multimap<String, String> multimap = getMultimap();
Collection<String> collection = multimap.values();
// multimap.values() 就是一個 集合
collection.forEach(System.out::println);
System.out.println("====================");
//asMap().values() 是按照鍵值分開的集合
// [a, b]
// [foo2, foo1]
// [bar1, bar2]
Collection<Collection<String>> values = multimap.asMap().values();
values.forEach(System.out::println);
}
}
實現(xiàn)鍵值對的雙向映射,解決傳統(tǒng)的維護兩個HashMap
經(jīng)常出現(xiàn)的問題
BiMap<K, V>是特殊的 Map:
- 可以用 inverse()反轉(zhuǎn) BiMap<K, V>的鍵值映射
- 保證值是唯一的,因此 values()返回 Set 而不是普通的 Collection
BiMap在鍵和值是唯一的時候很有用,可以隨意反轉(zhuǎn)
package com.byedbl.common.collect;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import org.junit.Test;
public class BiMapTest {
private BiMap<String,Integer> getBiMap() {
BiMap<String,Integer> biMap = HashBiMap.create();
biMap.put("語文", 60);
// biMap.put("語文", 70);
biMap.put("數(shù)學(xué)", 70);
biMap.put("數(shù)學(xué)", 80);
return biMap;
}
@Test
public void testPutWithSameValueFails() {
BiMap<String,Integer> biMap = getBiMap();
try {
//在 BiMap 中,如果你想把鍵映射到已經(jīng)存在的值,會拋出 IllegalArgumentException 異常
biMap.put("語文", 80);
// fail("Expected IllegalArgumentException");
} catch (IllegalArgumentException expected) {
System.out.println("expected error");
}
}
@Test
public void testReverse() {
BiMap<String,Integer> biMap = getBiMap();
biMap.inverse().forEach((k,v)-> {
System.out.println(k + " " + v);
});
}
@Test
public void testForcePutWithSameValueFails() {
BiMap<String,Integer> biMap = getBiMap();
// try {
//在 BiMap 中,如果你想把鍵映射到已經(jīng)存在的值,會拋出 IllegalArgumentException 異常
//可以用forcePut替代
biMap.forcePut("語文", 80);
// fail("Expected IllegalArgumentException");
// } catch (IllegalArgumentException expected) {
// }
}
}
解決多個鍵做索引的問題 Map<FirstName, Map<LastName, Person>>
Table 有如下幾種實現(xiàn):
- HashBasedTable:本質(zhì)上用 HashMap<R, HashMap<C, V>>實現(xiàn);
- TreeBasedTable:本質(zhì)上用 TreeMap<R, TreeMap<C,V>>實現(xiàn);
- ImmutableTable:本質(zhì)上用 ImmutableMap<R, ImmutableMap<C, V>>實現(xiàn);注:ImmutableTable 對稀疏或密集的數(shù)據(jù)集都有優(yōu)化。
- ArrayTable:要求在構(gòu)造時就指定行和列的大小,本質(zhì)上由一個二維數(shù)組實現(xiàn),以提升訪問速度和密集 Table 的內(nèi)存利用率。ArrayTable 與其他 Table 的工作原理有點不同,請參見 Javadoc 了解詳情。
package com.byedbl.common.collect;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import org.junit.Test;
import java.util.Map;
import java.util.Set;
public class TableTest {
private Table<String, String, String> getTable() {
Table<String, String, String> employeeTable = HashBasedTable.create();
//initialize the table with employee details
employeeTable.put("IBM", "101","Mahesh");
employeeTable.put("IBM", "102","Ramesh");
employeeTable.put("IBM", "103","Suresh");
employeeTable.put("Microsoft", "102","Sohan");
employeeTable.put("Microsoft", "112","Mohan");
employeeTable.put("Microsoft", "113","Ram");
employeeTable.put("TCS", "121","Ram");
employeeTable.put("TCS", "122","Shyam");
employeeTable.put("TCS", "123","Sunil");
return employeeTable;
}
@Test
public void testRow() {
Table<String, String, String> employeeTable = getTable();
Map<String,String> ibmEmployees = employeeTable.row("IBM");
System.out.println(ibmEmployees);
ibmEmployees = employeeTable.row("102");
System.out.println(ibmEmployees);
ibmEmployees = employeeTable.column("102");
System.out.println(ibmEmployees);
//get all the unique keys of the table
Set<String> employers = employeeTable.rowKeySet();
System.out.print("Employers: ");
for(String employer: employers){
System.out.print(employer + " ");
}
System.out.println();
System.out.println("-----------------------------");
//get a Map corresponding to 102
Map<String,String> EmployerMap = employeeTable.column("102");
for(Map.Entry<String, String> entry : EmployerMap.entrySet()){
System.out.println("Employer: " + entry.getKey() + ", Name: " + entry.getValue());
}
System.out.println("-----------------------------");
//get a Map corresponding to 102
EmployerMap = employeeTable.column("Ram");
for(Map.Entry<String, String> entry : EmployerMap.entrySet()){
System.out.println("Employer: " + entry.getKey() + ", Name: " + entry.getValue());
}
}
@Test
public void testRowMap() {
// IBM {101=Mahesh, 102=Ramesh, 103=Suresh}
// Microsoft {102=Sohan, 112=Mohan, 113=Ram}
// TCS {121=Ram, 122=Shyam, 123=Sunil}
Table<String, String, String> employeeTable = getTable();
Map<String, Map<String, String>> rowMap = employeeTable.rowMap();
rowMap.forEach((k,v)-> System.out.println(k + " " + v));
}
@Test
public void testColumnMap() {
// 101 {IBM=Mahesh}
// 102 {IBM=Ramesh, Microsoft=Sohan}
// 103 {IBM=Suresh}
// 112 {Microsoft=Mohan}
// 113 {Microsoft=Ram}
// 121 {TCS=Ram}
// 122 {TCS=Shyam}
// 123 {TCS=Sunil}
Table<String, String, String> employeeTable = getTable();
Map<String, Map<String, String>> columnMap = employeeTable.columnMap();
columnMap.forEach((k,v)-> System.out.println(k + " " + v));
}
@Test
public void testCellSet() {
Table<String, String, String> employeeTable = getTable();
Set<Table.Cell<String, String, String>> cells = employeeTable.cellSet();
cells.forEach(c-> System.out.println(c.getRowKey() + " " + c.getColumnKey()+ " " + c.getValue()));
}
}
傳入三個值,row,column,value
;既可以用row獲取,也可以用columnKey獲取值.遍歷用cellSet
-
ClassToInstanceMap
特殊的Map
,它的鍵是類型,而值是符合鍵所指類型的對象
package com.byedbl.common.collect;
import com.google.common.collect.ClassToInstanceMap;
import com.google.common.collect.MutableClassToInstanceMap;
import org.junit.Test;
public class ClassToInstanceMapTest {
@Test
public void testClassToInstanceMap() {
ClassToInstanceMap<Number> numberDefaults= MutableClassToInstanceMap.create();
for(int i=0;i<10;i++) {
numberDefaults.putInstance(Integer.class, i);
numberDefaults.putInstance(Long.class, (long) i);
}
Integer instance = numberDefaults.getInstance(Integer.class);
//9
System.out.println(instance);
System.out.println(numberDefaults.getInstance(Long.class));
}
}
存放類型與其對應(yīng)的值,后面的會覆蓋前面的,
-
RangeSet
區(qū)間,描述了一組不相連的、非空的區(qū)間。當(dāng)把一個區(qū)間添加到可變的RangeSet時,所有相連的區(qū)間會被合并,空區(qū)間會被忽略
package com.byedbl.common.collect;
import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;
import com.google.common.collect.TreeRangeSet;
import org.junit.Test;
public class RangeSetTest {
@Test
public void testRangeSet() {
RangeSet<Integer> rangeSet = TreeRangeSet.create();
rangeSet.add(Range.closed(1, 10)); // {[1,10]}
rangeSet.add(Range.closedOpen(11, 15));//不相連區(qū)間:{[1,10], [11,15)}
rangeSet.add(Range.closedOpen(15, 20)); //相連區(qū)間; {[1,10], [11,20)}
rangeSet.add(Range.openClosed(0, 0)); //空區(qū)間; {[1,10], [11,20)}
rangeSet.remove(Range.open(5, 10)); //分割[1, 10]; 結(jié)果為{[1,5], [10,10], [11,20)}
System.out.println(rangeSet);
}
}