集合分类 | 分类描述 | 结构类似 | 具体实现 | 实现描述 |
---|---|---|---|---|
不可变集合 | Java集合的对应不可变集合 | List | ImmutableList | 不可变的List集合 |
Set | ImmutableSet | 不可变的Set集合 | ||
Map | ImmutableMap | 不可变的Map集合 | ||
Multiset | 记录重复次数的集合 | Map | HashMultiset | 使用哈希表实现,不保证元素的顺序,可以存储 null 元素 |
TreeMultiset | 使用红黑树实现,会对元素进行排序,可以存储 null 元素 | |||
LinkedHashMultiset | 使用链表和哈希表实现,会保持元素的插入顺序,可以存储 null 元素 | |||
ConcurrentHashMultiset | 支持并发的HashMultiset,不保证元素的顺序,不可以存储 null 元素 | |||
ImmutableMultiset | 不可变的Multiset集合,线程安全,性能好 | |||
Multimap | 键可以映射到多个值的集合 | Map | ArrayListMultimap | 将键映射到ArrayList的集合。在同一个键对应的多个值被添加时,这些值会被存储在一个ArrayList中 |
HashMultimap | 使用哈希表来存储键值对。每个键可以映射到多个值,并且值的存储顺序是不确定的 | |||
LinkedListMultimap | 将键映射到LinkedList的集合。在同一个键对应的多个值被添加时,这些值会被存储在一个LinkedList中 | |||
LinkedHashMultimap | 使用LinkedHashMap来存储键值对。键和值的存储顺序会保持一致 | |||
TreeMultimap | 使用TreeMap来存储键值对。键和值会按照其自然顺序进行排序 | |||
ImmutableListMultimap | 将键映射到ImmutableList的集合。无法对其中的键值对进行修改 | |||
ImmutableSetMultimap | 将键映射到ImmutableSet的集合。无法对其中的键值对进行修改 | |||
BiMap | 支持键和值的双向查找的双向映射的集合 | Map | HashBiMap | 基于HashTable实现的双向映射,键值唯一且不允许为空 |
EnumBiMap | 专门用于处理枚举类型作为键的双向映射 | |||
EnumHashBiMap | 基于哈希表实现的枚举双向映射,提供枚举类型作为键的特殊支持 | |||
ImmutableBiMap | 不可变双向映射实现类,确保映射关系不可修改 | |||
Table | 类似二维表格的两个键的映射集合 | Map | HashBasedTable | 用 HashMap 实现内部的映射,它的行和列都不可重复。 |
TreeBasedTable | 使用 TreeMap 实现内部的映射,它的行和列会根据自然顺序进行排序。因此,使用 TreeBasedTable 可以保证表格的行和列都是有序的。 | |||
ArrayTable | 使用二维数组存储数据的Table,提供类似数组的接口 | |||
ImmutableTable | 是 Table 接口的不可变实现类,一旦创建就无法修改。 | |||
RangeSet | 非连续范围的集合 | List |
TreeRangeSet | 基于红黑树实现的可变范围集合,支持添加、删除和查询范围。 |
ImmutableRangeSet | 不可变范围集合,一旦创建后不能再添加、移除范围,支持高效的范围查询操作。 | |||
RangeMap | 不相交范围映射的集合 | Map |
TreeRangeMap | 使用树结构实现的 RangeMap,用于映射不相交的、非空的范围到某个值。 |
ImmutableRangeMap | 不可变的 RangeMap 实现类,用于映射不相交的、非空的范围到某个值,并且不可修改 |
可重复计数的集合,它允许元素的重复,并提供了一套操作和查询元素计数的方法。
使用场景:
频率统计:Multiset 可以用于统计元素在集合中出现的频率,以及对元素进行快速计数。例如,在统计单词频率、字母频率和商品销售量等场景中,可以使用 Multiset 进行元素计数和频率统计。
集合操作:Multiset 提供了一些集合操作的方法,例如求交集、并集和差集等。这些方法可以方便地进行元素集合操作,并且多次出现的元素数量也会得到合理处理。
去重操作:在某些场景中,需要对一些重复元素进行去重。虽然 Multiset 允许元素重复,但使用 Multiset 还是比使用 List 来处理去重更加方便。
Multiset的特性:
Multiset既有List的特性也有Map的特性:
Multiset的主要方法:
方法 | 描述 |
---|---|
int add(E element, int occurrences) | 将指定元素添加到 Multiset 中,增加次数为 occurrences。返回值为添加前该元素的计数。 |
int count(Object element) | 返回给定元素在此 Multiset 中的计数。如果元素不在 Multiset 中,返回 0。 |
int remove(Object element, int occurrences) | 从 Multiset 中移除指定数量的元素的计数。如果元素不在 Multiset 中,返回 0。 |
int setCount(E element, int count) | 将此 Multiset 实例中指定元素的计数设置为给定值 count。返回值为设置前该元素的计数。 |
boolean setCount(E element, int oldCount, int newCount) | 将指定元素在Multiset中的计数从旧值更改为新值。该方法会根据需要添加或删除元素以实现计数的更改。 如果元素的旧计数与指定的旧计数不匹配,则方法将抛出IllegalArgumentException。 |
int size() | 返回此 Multiset 中的总元素数(包括重复元素)。 |
Set |
返回此 Multiset 中不同元素的集合。 |
Set |
返回包含此 Multiset 中不同元素和计数的条目的集合。条目的类型为 Multiset.Entry |
boolean contains(Object element) | 判断 Multiset 中是否包含指定元素。 |
boolean isEmpty() | 判断 Multiset 是否为空。 |
boolean equals(Object obj) | 比较指定对象与 Multiset 是否相等。如果指定的对象也是 Multiset,并且包含相同的元素和计数,则返回 true。 |
void clear() | 从 Multiset 中移除所有元素。 |
Iterator |
返回一个迭代器,用于遍历 Multiset 中的元素。 |
boolean remove(Object element) | 从 Multiset 中移除一个元素。如果元素不在 Multiset 中,返回 false。 |
boolean removeAll(Collection> c) | 从 Multiset 中移除指定集合中的所有元素。返回值表示是否成功移除了任何元素。 |
boolean retainAll(Collection> c) | 仅保留 Multiset 中包含在指定集合中的元素,移除其他元素。返回值表示是否成功改变了 Multiset。 |
Multiset的实现类:
实现类型 | 类似的Map | 描述 |
---|---|---|
HashMultiset | HashMap | 使用哈希表实现。它不保证元素的顺序,可以存储 null 元素 |
TreeMultiset | TreeMap | 使用红黑树实现。它会对元素进行排序,可以存储 null 元素 |
LinkedHashMultiset | LinkedHashMap | 使用链表和哈希表实现。它会保持元素的插入顺序,可以存储 null 元素 |
ConcurrentHashMultiset | ConcurrentHashMap | 使用并发哈希表实现。它不保证元素的顺序,不可以存储 null 元素 |
ImmutableMultiset | ImmutableMap | 不可变集合,线程安全,性能好 |
当需要对元素进行频繁的添加、删除和计数操作,并不关心元素的顺序时,可以选择HashMultiset。
特点:
示例:
public static void main(String[] args) {
Multiset<String> multiset = HashMultiset.create();
multiset.add("apple", 10);
multiset.add("banana", 10);
multiset.add("apple");
System.out.println(multiset.count("apple"));
multiset.add("apple", 5);
System.out.println(multiset.count("apple"));
multiset.remove("banana");
System.out.println(multiset.count("banana"));
multiset.remove("banana",5);
System.out.println(multiset.count("banana"));
for (String s : multiset.elementSet()) {
System.out.println(s);
}
for (Multiset.Entry<String> entry : multiset.entrySet()) {
System.out.println("key:" + entry.getElement() + ",count:"+entry.getCount());
}
}
日志:
11
16
9
4
banana
apple
key:banana,count:4
key:apple,count:16
当需要对元素进行排序,并按照顺序访问元素和计数时,可以选择TreeMultiset。
特点:
示例:
public static void main(String[] args) {
Multiset<String> multiset = TreeMultiset.create();
multiset.add("orange");
multiset.add("banana");
multiset.add("apple");
multiset.add("banana");
multiset.add("apple");
// 打印排好序的元素及其计数
for (String element : multiset.elementSet()) {
System.out.println("Element: " + element + ", Count: " + multiset.count(element));
}
}
日志:
Element: apple, Count: 2
Element: banana, Count: 2
Element: orange, Count: 1
当需要保留元素插入的顺序,并按照插入顺序进行遍历和计数时,可以选择LinkedHashMultiset。
特点:
示例:
public static void main(String[] args) {
Multiset<String> multiset = LinkedHashMultiset.create();
multiset.add("orange");
multiset.add("banana");
multiset.add("apple");
multiset.add("banana");
multiset.add("apple");
// 打印排好序的元素及其计数
for (String element : multiset.elementSet()) {
System.out.println("Element: " + element + ", Count: " + multiset.count(element));
}
}
日志:
Element: orange, Count: 1
Element: banana, Count: 2
Element: apple, Count: 1
当需要在多线程环境下对Multiset进行操作时,可以选择ConcurrentHashMultiset。
特点:
示例:
public static void main(String[] args) {
Multiset<String> multiset = ConcurrentHashMultiset.create();
multiset.add("orange");
multiset.add("banana");
multiset.add("apple");
multiset.add("banana");
multiset.add("apple");
// 打印元素及其计数
for (String element : multiset.elementSet()) {
System.out.println("Element: " + element + ", Count: " + multiset.count(element));
}
}
日志
Element: orange, Count: 1
Element: banana, Count: 2
Element: apple, Count: 2
当需要对枚举类型元素进行频繁的添加、删除和计数操作,可以选择EnumMultiset。
特点:
示例:
public static void main(String[] args) {
Multiset<DayOfWeek> dayOfWeekMultiset = EnumMultiset.create(DayOfWeek.class);
// 模拟记录一周各个工作日出现的次数
dayOfWeekMultiset.add(DayOfWeek.MONDAY);
dayOfWeekMultiset.add(DayOfWeek.TUESDAY);
dayOfWeekMultiset.add(DayOfWeek.MONDAY);
dayOfWeekMultiset.add(DayOfWeek.WEDNESDAY);
dayOfWeekMultiset.add(DayOfWeek.MONDAY);
dayOfWeekMultiset.add(DayOfWeek.THURSDAY);
// 打印每个星期几的计数
for (DayOfWeek day : dayOfWeekMultiset.elementSet()) {
System.out.println("Day of week: " + day + ", Count: " + dayOfWeekMultiset.count(day));
}
}
日志:
Day of week: MONDAY, Count: 3
Day of week: TUESDAY, Count: 1
Day of week: WEDNESDAY, Count: 1
Day of week: THURSDAY, Count: 1
需要在程序中表示一组元素并且要求这组元素不可修改时,可以选择使用 ImmutableMultiset。
特点:
示例:
public static void main(String[] args) {
// 使用 of 方法创建不可变的 Multiset
Multiset<String> immutableMultiset = ImmutableMultiset.of("apple", "banana", "orange", "banana", "apple");
// 打印元素及其计数
for (String element : immutableMultiset.elementSet()) {
System.out.println("Element: " + element + ", Count: " + immutableMultiset.count(element));
}
}
日志
Element: apple, Count: 2
Element: banana, Count: 2
Element: orange, Count: 1
Multimap用于表示一对多的映射关系。在 Java 中,Map 是一对一的映射关系,即每个键对应一个值。而 Multimap 则可以让一个键对应多个值,这在很多场景下都是非常实用的。
使用场景:
Multimap的主要方法:
方法 | 描述 |
---|---|
int size() | Multimap 中所有键值对的总数。 |
boolean isEmpty() | Multimap 是否为空 |
boolean containsKey(Object key) | Multimap 是否包含指定的键 |
boolean containsValue(Object value) | Multimap 是否包含指定的值 |
boolean containsEntry(Object key, Object value) | Multimap 是否包含指定的键值对 |
boolean put(K key, V value) | 将指定的键值对加入 Multimap。返回值指示是否添加了新的键值对。 |
boolean remove(Object key, Object value) | 移除Multimap中指定的键值对。返回值指示是否移除了对应的键值对。 |
Collection |
返回指定键对应的值的集合,如果没有对应的键,则返回空集合。 |
boolean putAll(K key, Iterable extends V> values) | 将指定键对应的多个值加入 Multimap。 |
Collection |
移除Multimap中指定键对应的所有值,并返回这些值组成的集合。 |
void clear() | 清空Multimap中的所有键值对。 |
Collection |
替换 Multimap 中指定键对应的值。 |
Set |
返回 Multimap 中所有不重复的键组成的 Set。 |
Multiset |
返回 Multimap 中所有键组成的 Multiset。 |
Collection |
返回 Multimap 中所有值组成的集合。 |
Map |
返回一个包含所有键值对的 Map,其中每个键关联到的值集合是一个 Collection。 |
Multimap的主要实现类:
类 | 键行为类似 | 值行为类似 | 描述 |
---|---|---|---|
ArrayListMultimap | HashMap | ArrayList | 将键映射到ArrayList的集合。在同一个键对应的多个值被添加时,这些值会被存储在一个ArrayList中 |
HashMultimap | HashMap | HashSet | 使用哈希表来存储键值对。每个键可以映射到多个值,并且值的存储顺序是不确定的 |
LinkedListMultimap | LinkedHashMap | LinkedList | 将键映射到LinkedList的集合。在同一个键对应的多个值被添加时,这些值会被存储在一个LinkedList中 |
LinkedHashMultimap | LinkedHashMap | LinkedHashMap | 使用LinkedHashMap来存储键值对。键和值的存储顺序会保持一致 |
TreeMultimap | TreeMap | TreeSet | 使用TreeMap来存储键值对。键和值会按照其自然顺序进行排序 |
ImmutableListMultimap | ImmutableMap | ImmutableList | 将键映射到ImmutableList的集合。无法对其中的键值对进行修改 |
ImmutableSetMultimap | ImmutableMap | ImmutableSet | 将键映射到ImmutableSet的集合。无法对其中的键值对进行修改 |
适用于需要维护插入顺序并且允许重复的情况。
特点:
示例:
public static void main(String[] args) {
Multimap<String, Integer> multimap = ArrayListMultimap.create();
multimap.put("key1", 1);
multimap.put("key1", 2);
multimap.put("key2", 3);
multimap.put("key2", 4);
// 获取一个键对应的所有值
System.out.println(multimap.get("key1"));
System.out.println(multimap.get("key2"));
}
日志
[1, 2]
[3, 4]
适用于需要根据键快速查找值并确保键值对的唯一性。
特点:
示例:
public static void main(String[] args) {
Multimap<String, String> multimap = HashMultimap.create();
multimap.put("fruit", "apple");
multimap.put("fruit", "banana");
multimap.put("color", "red");
multimap.put("color", "blue");
// 获取一个键对应的所有值
System.out.println(multimap.get("fruit"));
System.out.println(multimap.get("color"));
}
日志
[banana, apple]
[red, blue]
适用于需要根据键保留插入顺序、允许重复值的情况。
特点:
public static void main(String[] args) {
Multimap<String, Integer> multimap = LinkedListMultimap.create();
multimap.put("fruit", 1);
multimap.put("fruit", 2);
multimap.put("color", 3);
multimap.put("color", 4);
// 获取一个键对应的所有值
System.out.println(multimap.get("fruit")); // [1, 2]
System.out.println(multimap.get("color")); // [3, 4]
}
日志
[1, 2]
[3, 4]
适用于需要根据键保留插入顺序、允许重复值的情况。
特点:
示例:
public static void main(String[] args) {
Multimap<String, String> multimap = LinkedHashMultimap.create();
multimap.put("fruit", "apple");
multimap.put("fruit", "banana");
multimap.put("color", "red");
multimap.put("color", "blue");
// 获取一个键对应的所有值
System.out.println(multimap.get("fruit")); // [apple, banana]
System.out.println(multimap.get("color")); // [red, blue]
}
日志
[apple, banana]
[red, blue]
适用于需要按键和值的顺序进行排序的情况。
特点:
示例:
public static void main(String[] args) {
Multimap<String, Integer> multimap = TreeMultimap.create();
multimap.put("fruit", 2);
multimap.put("fruit", 1);
multimap.put("color", 4);
multimap.put("color", 3);
// 获取一个键对应的所有值
System.out.println(multimap.get("fruit")); // [1, 2]
System.out.println(multimap.get("color")); // [3, 4]
}
日志
[1, 2]
[3, 4]
适用场景:
特点:
示例:
public static void main(String[] args) {
ImmutableListMultimap<String, Integer> multimap = ImmutableListMultimap.<String, Integer>builder()
.put("fruit", 1)
.put("fruit", 2)
.put("color", 3)
.put("color", 4)
.build();
System.out.println(multimap.get("fruit")); // [1, 2]
System.out.println(multimap.get("color")); // [3, 4]
}
日志
[1, 2]
[3, 4]
适用场景:
特点:
示例:
public class ImmutableSetMultimapExample {
public static void main(String[] args) {
ImmutableSetMultimap<String, Integer> multimap = ImmutableSetMultimap.<String, Integer>builder()
.put("fruit", 1)
.put("fruit", 2)
.put("color", 3)
.put("color", 4)
.build();
System.out.println(multimap.get("fruit")); // [1, 2]
System.out.println(multimap.get("color")); // [3, 4]
}
}
[1, 2]
[3, 4]
BiMap 是一种具有双向映射关系的数据结构。它能够同时提供键到值(key-to-value)和值到键(value-to-key)的映射,并保证键和值都是唯一的。
使用场景:
键值对的唯一性:BiMap 要求键和值都是唯一的,可以通过 BiMap 进行双向的键值映射。
反向查找:BiMap 提供了 inverse() 方法用于反转 BiMap 的键值映射,即通过值快速查找键。
特点:
主要方法:
方法 | 描述 |
---|---|
V put(K key, V value) | 将指定的键值对加入 BiMap。与普通 Map 不同,如果 BiMap 中已包含该值(无论是否作为值存在),则会把原映射的键删除,否则新增映射。 |
void putAll(Map extends K, ? extends V> map) | 将指定的 Map 中的所有键值对加入到当前的 BiMap 中。这个方法允许将另一个 Map 中的所有映射加入到当前的 BiMap 中,如果发生冲突,会覆盖旧的映射。 |
V forcePut(K key, V value) | 将指定的键值对加入 BiMap,如果 BiMap 中已包含该值(无论是否作为值存在),则删除原映射。 |
BiMap |
返回键值对调换的新的 BiMap。 |
相关实现类:
实现类 | 描述 |
---|---|
HashBiMap | 基于HashTable实现的双向映射,键值唯一且不允许为空 |
EnumBiMap | 专门用于处理枚举类型作为键的双向映射 |
EnumHashBiMap | 基于哈希表实现的枚举双向映射,提供枚举类型作为键的特殊支持 |
ImmutableBiMap | 不可变双向映射实现类,确保映射关系不可修改 |
使用哈希表实现了双向映射。
适用场景:
特点:
HashBiMap
不支持键或值为 null。示例:
public static void main(String[] args) {
BiMap<String, Integer> userId = HashBiMap.create();
userId.put("user1", 1);
userId.put("user2", 2);
// 通过键找值
System.out.println(userId.get("user1")); // 输出 1
// 通过值找键(在 BiMap 中,值是唯一的,可以直接通过值找到对应的键)
System.out.println(userId.inverse().get(2)); // 输出 user2
}
日志
1
user2
用于处理枚举类型作为键的双向映射。
适用场景:
特点:
示例:
public static void main(String[] args) {
BiMap<Month, DayOfWeek> weekdayToName = EnumBiMap.create(Month.class, DayOfWeek.class);
weekdayToName.put(Month.AUGUST, DayOfWeek.MONDAY);
weekdayToName.put(Month.JULY, DayOfWeek.SUNDAY);
System.out.println(weekdayToName.get(Month.AUGUST));
System.out.println(weekdayToName.inverse().get(DayOfWeek.SUNDAY));
}
日志
MONDAY
JULY
基于哈希表实现的枚举双向映射。
适用场景:
特点:
示例:
public static void main(String[] args) {
BiMap<Month, Integer> weekdayToName = EnumHashBiMap.create(Month.class);
weekdayToName.put(Month.AUGUST, 8);
weekdayToName.put(Month.JULY, 7);
System.out.println(weekdayToName.get(Month.AUGUST));
System.out.println(weekdayToName.inverse().get(7));
}
日志
8
JULY
ImmutableBiMap
是 BiMap
接口的不可变实现类。
适用场景:
特点:
示例:
public static void main(String[] args) {
BiMap<String, Integer> countryCodes = ImmutableBiMap.of(
"user1", 1,
"user2", 2
);
// 尝试修改不可变映射,会抛出 UnsupportedOperationException
countryCodes.put("user3", 3);
}
日志
Exception in thread "main" java.lang.UnsupportedOperationException
at com.google.common.collect.ImmutableMap.put(ImmutableMap.java:780)
at com.joker.test.guava.CollectionTest.main(CollectionTest.java:22)
Table 接口代表一个双重映射,类似于有两个键索引的数据表。它提供行和列之间的双重映射关系,并允许在行和列键对应的位置存储数据。
适用场景:
主要方法:
方法 | 描述 |
---|---|
boolean contains(Object rowKey, Object columnKey) | 判断表中是否包含指定的行键和列键。 |
boolean containsColumn(Object columnKey) | 判断表中是否包含指定的列键。 |
boolean containsRow(Object rowKey) | 判断表中是否包含指定的行键。 |
boolean containsValue(Object value) | 判断表中是否包含指定的值。 |
V get(Object rowKey, Object columnKey) | 返回指定行键和列键对应的值。 |
boolean isEmpty() | 判断表是否为空。 |
V put(R rowKey, C columnKey, V value) | 在指定的行键和列键位置存储值。 |
void putAll(Table extends R, ? extends C, ? extends V> table) | 将另一个表中的所有数据复制到当前表中。 |
V remove(Object rowKey, Object columnKey) | 移除指定行键和列键位置的值。 |
Map |
返回指定行键对应的所有列键和值的映射。 |
Se\t rowKeySet() | 返回所有行键的集合。 |
Map |
返回行键到列键和值的映射的映射。 |
Collection |
返回表中所有的值。 |
Set |
返回所有列键的集合。 |
Map |
返回指定列键对应的所有行键和值的映射。 |
Map |
返回列键到行键和值的映射的映射。 |
void clear() | 移除表中的所有映射关系。 |
boolean equals(Object obj) | 判断表是否与指定对象相等。 |
V putIfAbsent(R rowKey, C columnKey, V value) | 如果表中尚未存在指定的行键和列键,则将指定的值存储在该位置。 |
void clear() | 移除表中的所有映射关系。 |
void erase() | 移除表中的所有映射关系。 |
int hashCode() | 返回表的哈希码值。 |
boolean remove(Object rowKey, Object columnKey, Object value) | 移除指定行键和列键位置的指定值。 |
Map |
返回指定行键对应的所有列键和值的映射。 |
Map |
返回指定列键对应的所有行键和值的映射。 |
Map |
返回行键到列键和值的映射的映射。 |
Table |
返回所有列键到行键和值的映射的映射。 |
Map |
返回列键到行键和值的映射的映射。 |
int size() | 返回表中的映射关系数量。 |
相关实现类:
类 | 描述 |
---|---|
HashBasedTable | 用 HashMap 实现内部的映射,它的行和列都不可重复。对于没有任何映射的行和列,HashBasedTable 不会为其分配内存,因此在内存使用方面相对节约。 |
TreeBasedTable | 使用 TreeMap 实现内部的映射,它的行和列会根据自然顺序进行排序。因此,使用 TreeBasedTable 可以保证表格的行和列都是有序的。 |
ArrayTable | 使用二维数组存储数据的Table,提供类似数组的接口 |
ImmutableTable | 是 Table 接口的不可变实现类,一旦创建就无法修改。它可以通过静态方法 of 或者 copyOf 来创建表格,以及通过 cellSet 来查看表格的内容。 |
基于哈希表实现的 Table,使用 LinkedHashMap
适用场景:
示例:
public static void main(String[] args) {
Table<Integer, Integer, String> table = HashBasedTable.create();
table.put(1, 1, "A");
table.put(1, 2, "B");
table.put(2, 1, "C");
System.out.println(table.get(1, 1)); // 输出 A
System.out.println(table.row(1)); // 输出 {1=A, 2=B}
}
日志
A
{1=A, 2=B}
基于 TreeBasedTable
对于大规模数据的存储和检索,TreeBasedTable 可能导致性能问题,需要谨慎使用。
适用场景:
示例:
public static void main(String[] args) {
Table<String, String, String> table = TreeBasedTable.create();
table.put("row1", "col1", "A");
table.put("row2", "col2", "B");
System.out.println(table.get("row1", "col1"));
System.out.println(table.row("row2"));
}
日志
A
{col1=null, col2=B, col3=null}
使用二维数组来存储 Table 中的数据,提供了与 List 或数组类似的接口。
ArrayTable 是通过数组来存储数据的,需要提前知道行列的数量,不适用于动态大小的表格。数据量过大时,可能会占用较多内存空间。
适用场景:
示例:
public static void main(String[] args) {
List<String> rowKeys = Arrays.asList("row1", "row2", "row3");
List<String> columnKeys = Arrays.asList("col1", "col2", "col3");
Table<String, String, String> table = ArrayTable.create(rowKeys, columnKeys);
table.put("row1", "col1", "A");
table.put("row2", "col2", "B");
System.out.println(table.get("row1", "col1")); // 输出 A
System.out.println(table.row("row2")); // 输出 {col2=B}
}
日志
A
{col1=null, col2=B, col3=null}
是不可变的 Table 实现,所有数据一旦存入就无法修改。一旦构建完成,其中的数据不可被修改或添加,适用于静态的数据集合。
适用场景:
示例:
public static void main(String[] args) {
ImmutableTable<Integer, Integer, String> table = ImmutableTable.<Integer, Integer, String>builder()
.put(1, 1, "A")
.put(1, 2, "B")
.put(2, 1, "C")
.build();
System.out.println(table.get(1, 1)); // 输出 A
System.out.println(table.row(1)); // 输出 {1=A, 2=B}
}
日志
A
{1=A, 2=B}
RangeSet 是表示非连续范围的集合的接口。它以一种紧凑的方式表示一系列不相交的范围,并且提供了用于管理这些范围的方法。
使用场景:
区间操作:RangeSet 提供了一系列方法,例如添加区间、移除区间、合并区间、查询是否包含某个值等。这些操作可以方便地对区间进行增删改查的操作。
区间划分:在某些场景中,可能需要将一个范围划分为多个不重叠的子区间。RangeSet 可以很方便地进行区间的划分,并且可以基于不同的范围进行操作。
区间覆盖判断:RangeSet 提供了方法来判断某个范围是否完全覆盖了 RangeSet 中的某个子区间。这个功能在某些区间判断的场景中非常有用。
区间交集:RangeSet 可以计算两个 RangeSet 的交集,并返回包含两者交集的新 RangeSet。这在处理多个区间的交集操作时很有用。
特点:
主要方法:
方法 | 描述 |
---|---|
boolean contains(C value) |
判断范围集合是否包含指定的值。 |
boolean contains(Range |
判断范围集合是否完全包含指定的范围。 |
boolean encloses(Range |
判断范围集合是否完全包含指定的范围,包括边界。 |
boolean enclosesAll(RangeSet |
判断范围集合是否完全包含另一个范围集合的所有范围。 |
boolean intersects(Range |
判断范围集合是否与指定的范围相交 。 |
boolean isEmpty() |
判断范围集合是否为空。 |
Range |
返回包含指定值的最小范围。 |
Set |
返回范围集合中的所有范围。 |
Set |
返回范围集合的补集 ,即不包含在集合中的范围。 |
RangeSet |
返回范围集合与指定范围的交集 。 |
void add(Range |
向范围集合中添加指定的范围(自动合并 )。 |
void addAll(RangeSet |
向范围集合中添加另一个范围集合的所有范围(自动合并 )。 |
void remove(Range |
从范围集合中移除指定的范围。 |
void removeAll(RangeSet |
从范围集合中移除另一个范围集合的所有范围。 |
void clear() |
移除范围集合中的所有范围。 |
注意事项:
并集
)相关实现类:
类名 | 描述 |
---|---|
TreeRangeSet |
基于红黑树实现的可变范围集合,支持添加、删除和查询范围。 |
ImmutableRangeSet |
不可变范围集合,一旦创建后不能再添加、移除范围,支持高效的范围查询操作。 |
基于红黑树(TreeMap)实现的可变范围集合。它支持添加、移除和查询范围,并能高效地处理范围之间的交集、合并和补集操作。
特点:
内部使用红黑树(TreeMap)数据结构,范围按照包含的自然顺序进行存储。
支持高效的范围操作,如交集、合并和补集。
可变范围集合,可以添加、移除范围,是最常用的范围集合实现类。
使用场景:
对一组范围进行添加、删除和查询操作。
需要高效地检查两个范围集合之间的交集、合并和补集。
需要频繁地对范围集合进行修改。
示例:
public static void main(String[] args) {
TreeRangeSet<Integer> rangeSet = TreeRangeSet.create();
rangeSet.add(Range.closed(1, 8)); // 添加范围 [1, 8]
rangeSet.add(Range.closedOpen(10, 15)); // 添加范围 [10, 15)
rangeSet.add(Range.open(25, 30)); // 添加范围 (25, 30)
rangeSet.remove(Range.open(5, 7)); // 移除范围 (5, 7)
// 返回包含 12 的范围
Range<Integer> range = rangeSet.rangeContaining(12);
System.out.println(range);
// 包含指定值的最小范围
Range<Integer> integerRange = rangeSet.rangeContaining(26);
System.out.println(integerRange);
// 范围集合中的所有范围
Set<Range<Integer>> ranges = rangeSet.asRanges();
System.out.println(ranges);
// 范围集合的补集
RangeSet<Integer> complement = rangeSet.complement();
System.out.println(complement);
}
日志
[10..15)
(25..30)
[[1..5], [7..8], [10..15), (25..30)]
[(-∞..1), (5..7), (8..10), [15..25], [30..+∞)]
ImmutableRangeSet 是不可变的范围集合,一旦创建,就不能再添加、移除范围。它适合当范围集合的内容不需要改变时使用。
需要注意:ImmutableRangeSet 的范围不允许重叠。当我们尝试向 ImmutableRangeSet 中添加一个已覆盖已有范围的新范围时,将会抛出 IllegalArgumentException 异常。原因:ImmutableRangeSet 的设计旨在保证范围的不重叠性,以提高性能和确保范围集合的一致性。
特点:
使用场景:
示例:
public static void main(String[] args) {
ImmutableRangeSet<Integer> rangeSet = ImmutableRangeSet.<Integer>builder()
.add(Range.closed(1, 10)) // 包括 1 和 10
.add(Range.closedOpen(11, 15)) // 包括 11,不包括 15
.add(Range.open(20, 25)) // 不包括 20 和 25
.build();
System.out.println(rangeSet.asRanges());
System.out.println(rangeSet.contains(5));
System.out.println(rangeSet.contains(15));
System.out.println(rangeSet.subRangeSet(Range.closed(5, 20)));
}
日志
[[1..10], [11..15), (20..25)]
true
false
[[5..10], [11..15)]
RangeMap 接口表示将不相交的范围映射到值的集合。它对一系列不相交的范围进行值的映射,并提供了一系列方法来管理和查询这些映射关系。
使用场景:
范围操作:RangeMap 提供了一系列方法,例如添加范围、移除范围、查询范围内的键值对和范围合并。这些操作可以方便地对键值对进行增删改查的操作。
范围划分:在某些场景中,可能需要将一个范围划分为多个不重叠的子范围。RangeMap 可以很方便地进行范围的划分,并且可以基于不同的范围进行操作。
前缀子图搜索:RangeMap 支持通过一个键进行前缀搜索,并返回其所属范围的键值对集合。这个功能在某些场景中非常有用,例如用于搜索 IP 地址所属的 IP 段。
子区间计算:RangeMap 可以计算两个 RangeMap 的交集,并返回包含两者交集的新 RangeMap。这在处理多个范围的交集操作时很有用。
特点:
相关实现类:
实现类 | 描述 |
---|---|
TreeRangeMap | 使用树结构实现的 RangeMap,用于映射不相交的、非空的范围到某个值。 |
ImmutableRangeMap | 不可变的 RangeMap 实现类,用于映射不相交的、非空的范围到某个值,并且不可修改。 |
TreeRangeMap 是 Guava 中 RangeMap 接口的实现类,用于将不相交的、非空的范围映射到某个值。基于树的数据结构来存储范围映射,提供高效的范围查询和范围映射操作。
特点:
使用场景:
示例:
public static void main(String[] args) {
TreeRangeMap<Integer, String> rangeMap = TreeRangeMap.create();
rangeMap.put(Range.closed(1, 10), "A");
rangeMap.put(Range.closed(11, 20), "B");
System.out.println(rangeMap.get(5)); // 输出 A
System.out.println(rangeMap.get(15)); // 输出 B
}
日志
A
B
ImmutableRangeMap 是不可变的 RangeMap 实现类,用于将不相交的、非空的范围映射到某个值,并且不可修改。
特点:
使用场景:
示例:
public static void main(String[] args) {
ImmutableRangeMap<Integer, String> rangeMap = ImmutableRangeMap.<Integer, String>builder()
.put(Range.closed(1, 10), "A")
.put(Range.closed(11, 20), "B")
.build();
System.out.println(rangeMap.get(5)); // 输出 A
System.out.println(rangeMap.get(15)); // 输出 B
}
日志
A
B
集合工具类 | 描述 |
---|---|
Collections2 | 提供了对集合进行过滤、转换等操作方法 |
Lists | 处理 List 集合的工具类,提供了便捷的静态工厂方法和操作方法 |
Sets | 处理 Set 集合的工具类,提供了创建和操作集合的静态方法 |
Maps | 处理 Map 集合的工具类,提供了创建和操作 Map 集合的静态方法 |
Multisets | 处理 Multiset 的工具类,提供了对 Multiset 进行操作的方法 |
Multimaps | 处理 Multimap 的工具类,提供了对 Multimap 进行操作的方法 |
Table | 处理表格数据的工具类,用于处理二维数据结构 |
Range | 处理数值范围,提供了创建范围、判断范围关系、获取范围的交集、并集等方法 |
方法签名 | 描述 |
---|---|
filter(Collection unfiltered, Predicate super E> predicate) | 过滤集合中满足给定谓词的元素 |
filter(Collection unfiltered, Predicate super E> predicate, Class type) | 过滤并将结果转换为指定类型的集合 |
transform(Collection fromCollection, Function super F,? extends T> function) | 将集合中的元素进行转换 |
transformAndConcat(Iterable fromIterable, Function super F,? extends Iterable extends T>> function) | 转换并合并多个集合的元素 |
方法签名 | 描述 |
---|---|
cartesianProduct(List extends E>… lists) | 返回列表的笛卡尔积 |
partition(List list, int size) | 将列表划分为指定大小的子列表 |
reverse(List list) | 反转列表的元素顺序 |
transform(List fromList, Function super F,? extends T> function) | 将列表中的元素进行转换 |
方法签名 | 描述 |
---|---|
cartesianProduct(Set extends B>… sets) | 返回集合的笛卡尔积 |
combinations(Set set, int size) | 返回集合中指定大小的所有组合 |
difference(Set set1, Set> set2) | 返回 set1 中有而 set2 中没有的元素 |
intersection(Set> set1, Set> set2) | 返回两个集合的交集 |
powerSet(Set set) | 返回集合的所有子集 |
symmetricDifference(Set extends E> set1, Set extends E> set2) | 返回两个集合的对称差集 |
union(Set extends E> set1, Set extends E> set2) | 返回两个集合的并集 |
方法签名 | 描述 |
---|---|
filterEntries(Map |
返回一个包含只有满足给定谓词的键值对的视图 |
filterKeys(Map |
返回一个包含只有满足给定谓词的键的视图 |
filterValues(Map |
返回一个包含只有满足给定谓词的值的视图 |
transformEntries(Map |
返回一个包含对原始映射中的每个键值对应用转换器后的结果的视图 |
transformValues(Map |
返回一个包含对原始映射中的每个值应用函数后的结果的视图 |
uniqueIndex(Iterable values, Function super V, K> keyFunction) | 返回一个将给定值集合中每个值的 keyFunction 的结果作为键映射到对应值的视图 |
方法签名 | 描述 |
---|---|
copyHighestCountFirst(Multiset multiset) | 返回一个元素按计数从高到低排序的不可变 Multiset |
filter(Multiset unfiltered, Predicate super E> predicate) | 返回一个包含只有满足给定谓词的元素的 Multiset 的视图 |
filterEntries(Multiset unfiltered, Predicate super Multiset.Entry> entryPredicate) | 返回一个包含只有满足给定谓词的元素和相应计数的 Multiset 的视图 |
transformEntries(Multiset fromMultiset, Multisets.EntryTransformer super K1, V1> transformer) | 返回一个包含对原始 Multiset 中的每个元素和相应计数应用转换器后的结果的 Multiset 的视图 |
transform(Multiset fromMultiset, Function super F, ? extends T> function) | 返回一个包含对原始 Multiset 中的每个元素应用函数后的结果的 Multiset 的视图 |
方法签名 | 描述 |
---|---|
invertFrom(Multimap |
将源 Multimap 的键值对颠倒并放入目标 Multimap |
newListMultimap(Map |
创建一个基于 Map 的新的、空的 ListMultimap 实例 |
newSetMultimap(Map |
创建一个基于 Map 的新的、空的 SetMultimap 实例 |
方法签名 | 描述 |
---|---|
create() | 创建一个新的、空的可变 Table 实例 |
create(RowKeyGenerator super R> rowKeyGenerator, ColumnKeyGenerator super C> columnKeyGenerator) | 根据提供的行键生成器和列键生成器创建一个新的、空的可变 Table 实例 |
create(Table extends R, ? extends C, ? extends V> table) | 根据提供的表创建一个新的、可变的 Table 实例 |
rowKeySet() | 返回行键的 Set 视图 |
columnKeySet() | 返回列键的 Set 视图 |
contains(Object rowKey, Object columnKey) | 返回表是否包含指定的行键和列键 |
cellSet() | 返回表中的单元格集合 |
row(Object rowKey) | 返回指定行的映射 |
column(Object columnKey) | 返回指定列的映射 |
put(R rowKey, C columnKey, V value) | 在指定的行和列中将值放入表 |
remove(Object rowKey, Object columnKey) | 移除指定行和列中的值 |
clear() | 清空表中的所有元素 |
size() | 返回表中的键值对数量 |
方法签名 | 描述 |
---|---|
all() | 创建一个包含所有值的无限范围 |
atLeast(Cut |
创建一个至少包含指定下界的范围 |
atMost(Cut |
创建一个至多包含指定上界的范围 |
closed(Cut |
创建一个包含下界和上界的范围 |
closedOpen(Cut |
创建一个包含下界但不包含上界的范围 |
openClosed(Cut |
创建一个包含上界但不包含下界的范围 |
open(Cut |
创建一个既不包含下界也不包含上界的范围 |
closed(C lower, C upper) | 创建一个闭合的范围 |
closedOpen(C lower, C upper) | 创建一个左闭右开的范围 |
openClosed(C lower, C upper) | 创建一个左开右闭的范围 |
open(C lower, C upper) | 创建一个开放的范围 |
canonical(DiscreteDomain |
如果范围是有限的,则返回一个规范有限范围的视图,否则返回自身 |
hasLowerBound() | 返回范围是否具有下界 |
hasUpperBound() | 返回范围是否具有上界 |
lowerBoundType() | 返回下界的类型 |
upperBoundType() | 返回上界的类型 |
lowerBound | 返回下界的值 |
upperBound | 返回上界的值 |
isConnected(Range |
返回范围是否与另一个范围相连 |
intersection(Range |
返回当前范围和另一个范围的交集 |
span(Range |
返回当前范围和另一个范围的并集 |
contains(C value) | 返回范围是否包含指定值 |
containsAll(Iterable extends C> values) | 返回范围是否包含指定集合的所有值 |
encloses(Range |
返回当前范围是否完全包含另一个范围 |
enclosesAll(Iterable extends Range |
返回当前范围是否完全包含指定集合中的所有范围 |
intersection(Cut |
返回当前范围和另一个单值的交集 |