前言
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底层使用HashMapLinkedHashMultiSet底层使用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,想要根据他来创建一个不可变的List1
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);