Guava 集合工具类
文章目录
Multiset
名如其意,多重Set,意思是可以重复添加,Multiset可以使用count函数将重复添加的key值进行统计。
特点:
- 这就像
ArrayList<E>
没有排序约束:排序无关紧要。 - 这就像一个
Map<E, Integer>
,带有元素和计数。
Guava 的Multiset
API 结合了对以下方式的思考:
- 当被视为一个 普通的集合(
Collection
)时,Multiset
其行为很像一个 无序的ArrayList
:- 调用
add(E)
添加给定元素的单次出现。 - Multiset的
iterator()
迭代每个元素的每次出现。 - Multiset的
size()
是所有元素的所有出现的总数。
- 调用
- 额外的查询操作以及性能特征将其视作为
Map<E, Integer>
.count(Object)
返回与该元素关联的计数。对于HashMultiset
,count 是 O(1),对于TreeMultiset
,count 是 O(log n),等等。entrySet()
返回Set<Multiset.Entry<E>>
,其工作方式类似于 的 entrySetMap
。elementSet()
返回Set<E>
多重集的不同元素 ,就像keySet()
a一样Map
。- 实现的内存消耗
Multiset
与不同元素的数量成线性关系。
值得注意的是MultiSet并不是一个Map,尽管它实现了类似于Map<E, Integer>
的功能,MultiSet是一个集合类型,实现了Collection接口,实现了Collection接口规范。
实现
Guava 提供了很多 的实现Multiset
,大致对应 JDK 的 Map 实现。
Map | MutlliSet | 支持null 元素 |
---|---|---|
HashMap | HashMultiset | 是 |
TreeMap | TreeMultiset | 是 |
LinkedHashMap | LinkedHashMultiset | 是 |
ConcurrentHashMap | ConcurrentHashMultiset | 否 |
ImmutableMap | ImmutableMultiset | 否 |
SortedMultiset
是Multiset
接口的一种变体,它支持在指定范围内有效地获取子多集。TreeMultiset
实现SortedMultiset
接口。
SortedMultiset<String> sortedMultiset= TreeMultiset.create();
//后面的数字occurrences代表出现的次数,可以手动指定,不指定将自动统计
sortedMultiset.add("a",2);
sortedMultiset.add("b",4);
sortedMultiset.add("c",5);
sortedMultiset.add("d",7);
System.out.println(sortedMultiset.count("b"));
//截取子结果集,BoundType.OPEN表示开区间,不包含临界值,BoundType.CLOSE表示闭区间,包含临界值
System.out.println(sortedMultiset.subMultiset("a",BoundType.OPEN,"d",BoundType.CLOSED));
输出:
4
[b x 4, c x 5, d x 7]
Multimap
多重Map,可以重复添加key和键值,内部实现为Map<K, Collection<V>>
Multimap<K,V>相当于Map<K, List<V>>
或者Map<K, Set<V>>
创建 Multimap 一种是 用 MultimapBuilder
,它允配置键和值的表示方式。例如:
// creates a ListMultimap with tree keys and array list values
ListMultimap<String, Integer> treeListMultimap =
MultimapBuilder.treeKeys().arrayListValues().build();
// creates a SetMultimap with hash keys and enum set values
SetMultimap<Integer, MyEnum> hashEnumMultimap =
MultimapBuilder.hashKeys().enumSetValues(MyEnum.class).build();
Multimap<K, V>
虽然内部使用Map<K, Collection<V>>
实现 ,但是与Map有些许的不同点:
Multimap.get(key)
总是返回一个非空的的集合。这并不意味着 multimap 会花费与键关联的任何内存,而是返回的集合是一个视图,允许您根据需要添加与键的关联。- 如果你更喜欢像
Map
一样不存在值的时候返回null
,请使用asMap()
视图获取。
Multimap.entries()
返回key的entry。如果想使用key-value的entry,请使用asMap().entrySet()
.Multimap.size()
返回整个Multimap中的条目数,而不是键的数量。使用Multimap.keySet().size()
获取键的数量。
另外一种就是直接使用实现类进行create();
实现
实现类 | 键相当于… | 值相当于.. |
---|---|---|
ArrayListMultimap | HashMap | ArrayList |
HashMultimap | HashMap | HashSet |
LinkedListMultimap * | LinkedHashMap``* | LinkedList``* |
LinkedHashMultimap ** | LinkedHashMap | LinkedHashSet |
TreeMultimap | TreeMap | TreeSet |
ImmutableListMultimap | ImmutableMap | ImmutableList |
ImmutableSetMultimap | ImmutableMap | ImmutableSet |
BiMap
双向Map,我们经常有需要用到值映射回key的操作,比如:
Map<String, Integer> nameToId = Maps.newHashMap();
Map<Integer, String> idToName = Maps.newHashMap();
nameToId.put("Bob", 42);
idToName.put(42, "Bob");
上面这种情况一般需要构造两个Map,并且要使它们put的值都保持同步,如果忘了或者粗心都会导致bug,还有可能是重复的key值导致的bug。BigMap就是为了解决这种现象而设计的。
BiMap特点:
- 支持值(value)获取键(key),只需要调用
inverse()
函数即可 - 确保键值唯一,BiMap.put(key, value)存在重复的key的时候会抛出
IllegalArgumentException
异常,如果你不想抛异常可以使用BiMap.forcePut(key, value)
强制put进去,避免键值重复导致的bug。
BiMap<String, Integer> userId = HashBiMap.create();
...
String userForId = userId.inverse().get(id);
实现
Key-Value Map实现 | Value-Key Map实现 | BiMap实现 |
---|---|---|
HashMap | HashMap | HashBiMap |
ImmutableMap | ImmutableMap | ImmutableBiMap |
EnumMap | EnumMap | EnumBiMap |
EnumMap | HashMap | EnumHashBiMap |
Table
通常我们要用到多重映射的时候会这样使用Map<String,Map<String,String>>
,这样显得很臃肿,也很难用,Guava提供了新的集合类型Table,Table引用了表格的概念,行,列值代替双重Map。
Table<String,String,String>
第一个值代表是行(row),第二个代表列(column),第三个值代表值(value)通过一行一列可以确定一个值。
Table<String, String, Integer> table = HashBasedTable.create();
table.put("行1", "列1", 4);
table.put("行2", "列2", 20);
table.put("行3", "列2", 5);
table.row("行1"); // 返回Map结果集 列1 to 4, 列2 to 20
table.column("列2"); // 返回Map结果集 行2 to 20, 行3 to 5
Table
支持多种视图,让您可以从任何角度使用数据,包括
rowMap()
, 将 aTable<R, C, V>
视为Map<R, Map<C, V>>
. 同样,rowKeySet()
返回一个Set<R>
.row(r)
返回一个非 nullMap<C, V>
。写入Map
将写入底层Table
。- 提供了类似的列方法:
columnMap()
、columnKeySet()
和column(c)
。(基于列的访问比基于行的访问效率稍低。) cellSet()
将 的视图返回Table
为一组Table.Cell<R, C, V>
.Cell
很像Map.Entry
,但区分行键和列键。
实现
HashBasedTable
, 基本对应HashMap<R, HashMap<C, V>>
.TreeBasedTable
, 基本对应TreeMap<R, TreeMap<C, V>>
.ImmutableTable
ArrayTable
,这要求在构建时指定完整的行和列,但在表密集时由二维数组支持以提高速度和内存效率。ArrayTable
与其他实现方式有些不同;
不可变集合
为什么使用不可变集合?
不可变对象有很多优点,包括:
- 不受信任的库可以安全使用。
- 线程安全:可以被许多线程使用,没有竞争条件的风险。
- 不需要支持可变性,可以尽量节省空间和时间的开销, 所有的不可变集合实现都比可变集合更加有效的利用内存。
制作对象的不可变副本是一种很好的防御性编程技术。Guava 为每种标准类型提供简单易用的不可变版本 Collection
,包括 Guava 自己的Collection
变体。
JDK 提供了Collections.unmodifiableXXX
方法,但是没有做到真正的不可变,当你引用对象添加或删除值的时候,不可变对象也会跟着变化,比如:
List<String> list = new ArrayList<String>();
list.add("a");
list.add("b");
list.add("c");
List<String> unmodifiableList = Collections.unmodifiableList(list);
list.add("d");
System.out.println(unmodifiableList);
我们对list添加了一个元素,结果输出不可变集合也跟着变化了,这并不是我们期望得到的结果。
使用Guava的不可变集合可以解决这个问题。
提示:当你不希望修改集合或希望集合保持不变时,最好将其防御性地复制到不可变集合中。每个 Guava 不可变集合实现都拒绝空值。要添加null元素的话可以使用Collections.unmodifiableList的实现。
如何去使用
可以ImmutableXXX
通过多种方式创建集合:
- 使用该
copyOf
方法,例如,ImmutableSet.copyOf(set)
of
例如,使用该方法,ImmutableSet.of("a", "b", "c")
或ImmutableMap.of("a", 1, "b", 2)
- 使用
Builder
,例如:
public static final ImmutableSet<Color> GOOGLE_COLORS =
ImmutableSet.<Color>builder()
.addAll(WEBSAFE_COLORS)
.add(new Color(0, 191, 255))
.build();
所有不可变集合都有一个asList()方法提供ImmutableList视图,来帮助你用列表形式方便地读取集合元素。例如,你可以使用sortedSet.asList().get(k)从ImmutableSortedSet中读取第k个最小元素。
实现
接口 | JDK /Guava | 不可变实现 |
---|---|---|
Collection | JDK | ImmutableCollection |
List | JDK | ImmutableList |
Set | JDK | ImmutableSet |
SortedSet /NavigableSet | JDK | ImmutableSortedSet |
Map | JDK | ImmutableMap |
SortedMap | JDK | ImmutableSortedMap |
Multiset | Guava | ImmutableMultiset |
SortedMultiset | Guava | ImmutableSortedMultiset |
Multimap | Guava | ImmutableMultimap |
ListMultimap | Guava | ImmutableListMultimap |
SetMultimap | Guava | ImmutableSetMultimap |
BiMap | Guava | ImmutableBiMap |
ClassToInstanceMap | Guava | ImmutableClassToInstanceMap |
Table | Guava | ImmutableTable |
参考资料
https://github.com/google/guava/wiki/ImmutableCollectionsExplained
https://github.com/google/guava/wiki/NewCollectionTypesExplained
Leave a Reply