前言
Collections
应该是最最常用的了
MultiMap
MultiMap
是一个接口,形象的用JDK中的形式解释就是Map<K, Collection<V>>
MultiMap
有很多的实现类
HashMultiMap
需要注意的是,HashMultimap
每个key
对应的value
的集合是一个Set
所以下面这个输出是
{World=[2], Hello=[1, 3]}
1 | Multimap<String, Integer> multimap = HashMultimap.create(); |
LinkedListMultimap
上面的value
是个Set
集合,但是如果我们需要是个List
集合呢
就可以使用LinkedListMultimap
这个方法
输出
{Hello=[1, 3, 3], World=[2]}
1 | Multimap<String, Integer> multimap = LinkedListMultimap.create(); |
TreeMultimap
和HashMultiMap
一样,也是value
存的是个Set
集合,只是这个使用的是红黑树为底层节点。
MultiSet
这个接口的作用大概和Apache Common
的Bag
的概念类似。
虽然名字里带Set
,但是其实没有实现Set接口。
比如1
2
3
4
5
6
7
8
9Multiset<String> multiset = LinkedHashMultiset.create();
multiset.add("1");
multiset.add("1");
multiset.add("1");
multiset.add("2");
multiset.add("2");
multiset.add("3");
System.out.println(multiset.count("1")); // 3
System.out.println(multiset.elementSet()); // 1 2 3
理解为Bag
,我们往包里放了3个1,2个2,1个3。
调用Count
我们可以得到里面究竟有多少1。
MultiSet
的主要实现有三个类
HashMultiSet
底层使用HashMap
LinkedHashMultiSet
底层使用LinkedHashMap
,就是元素顺序就依次添加进去的TreeMultiSet
底层使用的TreeMap
BiMap
正常我们维护一个K,V
的关系是选用一个Map
,但是如果我们不仅仅需要K,V 还需要一个V,K的关系呢 也就是正向是个Map,全部反过来也是个Map。
很多人会New两个Map,然后正着放一遍,反着再放一遍1
2
3
4
5Map<String, Integer> nameToId = Maps.newHashMap();
Map<Integer, String> idToName = Maps.newHashMap();
nameToId.put("Bob", 42);
idToName.put(42, "Bob");
但是这样会有问题,因为Map
中的value
并不保证是个Set
集合。
Guava
提供了BiMap
接口,使得我们不需要创建两个Map
,而且也保证Value
是个Set
集合。1
2
3
4
5
6
7
8BiMap<String, Integer> biMap = HashBiMap.create();
biMap.put("Hello", 2);
biMap.put("World", 3);
biMap.put("Java", 4);
System.out.println(biMap);
BiMap<Integer, String> inverse = biMap.inverse();
System.out.println(inverse);
如果我们需要反过来的Map
,只需要调用inverse
方法就行。
Immutable Collections
在原生的JDK
中,似乎并没有想严格的区分可变集合和不可变集合。
但是如果你阅读过Effective Java
的话,里面在第十五条有提到不可变的对象的好处
- 不可变的类比可变类更加易于设计、实现和使用
- 不可变对象本质上是线程安全的,它们不要求同步
- 首先作为Map的key等这种场景,肯定是适用的
- 因为无法修改,所以在多线程下的迭代不会抛出异常
就像String
推荐作为Map
的key
一样,String
天生是不可变类,易用且不会出现什么问题。
那么怎么理解不可变集合类的用法呢
个人觉得就像StringBuilder
和String
的用法一样
ImmutableList
创建不可变的List
同时这个类的声明中还带有RandomAccess
接口
所以底层是使用了Array
来存储元素
如果不清楚我们需要多少元素,可以先创建一个builder
builder()1
2
3
4
5
6
7
8
9
10
11ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("Hello");
arrayList.add("World");
arrayList.add("Java");
ImmutableList.Builder<String> stringBuilder = ImmutableList.<String>builder()
.add("Hello")
.add("world");
.addAll(arrayList);
stringBuilder.add("Java");
ImmutableList<String> strings = stringBuilder.build();
of()
或者我们可以直接调用of
方法如果我们知道已经知道成员变量。1
ImmutableList<String> list = ImmutableList.of("Hello", "World", "Java");
因为ImmutableList
是实现了List
接口,所以我们这样也行1
List<String> list = ImmutableList.of("Hello", "World", "Java");
如果我们拿到的是List
方法,那么他的企图修改List的方法已经被标记为@Deprecated
并且如果强行调用会抛出UnsupportedOperationException
copyOf()
如果我们已经有了一个List,想要根据他来创建一个不可变的List
1
2
3
4
5ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("Hello");
arrayList.add("World");
arrayList.add("Java");
ImmutableList<String> immutableList = ImmutableList.copyOf(arrayList);
sortedCopyOf()
之前的List
是可以进行Collections.sort()
方法进行修改的
但是ImmutableList
是不可变的,所以不可以进行sort
,或者说在build
完成之前是不可以进行sort
的
那么我们可以调用sortedCopyOf()
方法进行构建
那么如果我使用的是Builder
方法进行构建,可不可以在build()
之前对里面的元素进行排序呢?
似乎没看到方法。
ImmutableSet
其实和上面的ImmutableList
差不是很多,就不讲了。
ImmutableBiMap
同时BiMap
也提供了不可变的类型
我们可以使用Builder
类方法或者of
方法去进行创建1
2
3
4
5
6
7
8ImmutableBiMap.Builder<String, Integer> builder = ImmutableBiMap.builder();
builder.put("Hello", 2);
builder.put("World", 3);
builder.put("Java", 4);
ImmutableBiMap<String, Integer> biMap = builder.build();
System.out.println(biMap);
BiMap<Integer, String> inverse = biMap.inverse();
System.out.println(inverse);