更新
This commit is contained in:
parent
bc5d4921ef
commit
ead3d16257
637
java/Guava中的类型增强.md
Normal file
637
java/Guava中的类型增强.md
Normal file
@ -0,0 +1,637 @@
|
|||||||
|
# Guava中的类型增强
|
||||||
|
|
||||||
|
Map - Table、BiMap、Multimap、RangeMap、ClassToInstanceMap
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### 1. 简介[#](https://www.cnblogs.com/cao-lei/p/17806222.html#3979976375)
|
||||||
|
|
||||||
|
日常开发中使用Map时经常会遇到很多复杂的处理场景,例如:多个键的Map、不仅可以根据键获取值也可以根据值获取键且不用遍历、重复键的Map、数字等范围内映射相同的值、内存中缓存对象等,Guava提供了以上场景的解决方案。
|
||||||
|
|
||||||
|
| 场景 | 解决方案 | 具体实现 |
|
||||||
|
| ------------------------------------------------ | ------------------ | ------------------------------------------------------------ |
|
||||||
|
| 多个键的Map | Table | HashBasedTable、TreeBasedTable、ImmutableTable |
|
||||||
|
| 不仅可以根据键获取值也可以根据值获取键且不用遍历 | BiMap | HashBiMap、ImmutableBiMap |
|
||||||
|
| 重复键的Map | Multimap | ArrayListMultimap、LinkedListMultimap、LinkedHashMultimap、ImmutableListMultimap、ImmutableSetMultimap |
|
||||||
|
| 数字等范围内映射相同的值 | RangeMap | TreeRangeMap、ImmutableRangeMap |
|
||||||
|
| 内存中缓存对象 | ClassToInstanceMap | MutableClassToInstanceMap、ImmutableClassToInstanceMap |
|
||||||
|
|
||||||
|
本博客将详细描述具体的示例代码。
|
||||||
|
|
||||||
|
#### 2. 添加依赖[#](https://www.cnblogs.com/cao-lei/p/17806222.html#1443701749)
|
||||||
|
|
||||||
|
Maven项目pom.xml中添加依赖:
|
||||||
|
|
||||||
|
```xml
|
||||||
|
Copy<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>32.0.0-jre</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. Tbale - 表结构数据[#](https://www.cnblogs.com/cao-lei/p/17806222.html#848306248)
|
||||||
|
|
||||||
|
官方注释翻译:将一对有序键(称为行键和列键)与单个值相关联的集合。
|
||||||
|
示例代码(需求: 记录各个公司每个部门的人数):
|
||||||
|
|
||||||
|
```swift
|
||||||
|
Copy// HashMap
|
||||||
|
Map<String, Integer> deptMap = new HashMap<>();
|
||||||
|
deptMap.put("A部门", 10);
|
||||||
|
deptMap.put("B部门", 20);
|
||||||
|
Map<String, Map<String, Integer>> companyMap = new HashMap<>();
|
||||||
|
companyMap.put("xx公司", deptMap);
|
||||||
|
// HashMap 获取值
|
||||||
|
Integer val = companyMap.get("xx公司").get("A部门");
|
||||||
|
System.out.println("HashMap 获取值: " + val);
|
||||||
|
|
||||||
|
// 创建Hash类型Table, 基于Hash表实现
|
||||||
|
// Table<R, C, V>中三个泛型: R-行, C-列, V-值
|
||||||
|
Table<String, String, Integer> hashTable = HashBasedTable.create();
|
||||||
|
hashTable.put("xx公司", "A部门", 10);
|
||||||
|
hashTable.put("xx公司", "B部门", 20);
|
||||||
|
hashTable.put("xx公司", "C部门", 30);
|
||||||
|
|
||||||
|
System.out.println("\nHash Table: " + hashTable);
|
||||||
|
|
||||||
|
// 创建Tree类型Table, 基于红黑树实现
|
||||||
|
Table<String, String, Integer> treeTable = TreeBasedTable.create();
|
||||||
|
treeTable.put("xx公司", "C部门", 30);
|
||||||
|
treeTable.put("xx公司", "B部门", 20);
|
||||||
|
treeTable.put("xx公司", "A部门", 10);
|
||||||
|
|
||||||
|
System.out.println("\nTree Table: " + treeTable);
|
||||||
|
|
||||||
|
// 创建不可变Table, 无法新增、更新或删除
|
||||||
|
Table<String, String, Integer> immutableTable = ImmutableTable.<String, String, Integer>builder()
|
||||||
|
.put("xx公司", "C部门", 30)
|
||||||
|
.put("xx公司", "B部门", 20)
|
||||||
|
.put("xx公司", "A部门", 10)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
System.out.println("\nImmutable Table: " + immutableTable);
|
||||||
|
|
||||||
|
// Table 获取值
|
||||||
|
Integer val2 = hashTable.get("xx公司", "A部门");
|
||||||
|
System.out.println("\nTable 获取值: " + val2);
|
||||||
|
|
||||||
|
// Table 删除值
|
||||||
|
Integer remove = hashTable.remove("xx公司", "C部门");
|
||||||
|
System.out.println("\nTable 删除值: " + remove);
|
||||||
|
|
||||||
|
// 根据行获取列和值映射
|
||||||
|
Map<String, Integer> columnvalueMap = hashTable.row("xx公司");
|
||||||
|
System.out.println("\nTable 列和值 映射: " + columnvalueMap);
|
||||||
|
|
||||||
|
// 根据列获取行和值映射
|
||||||
|
Map<String, Integer> rowvalueMap = hashTable.column("A部门");
|
||||||
|
System.out.println("\nTable 行和值 映射: " + rowvalueMap);
|
||||||
|
|
||||||
|
// 获取key集合
|
||||||
|
Set<String> rowKeySet = hashTable.rowKeySet();
|
||||||
|
System.out.println("\nTable Row key 集合: " + rowKeySet);
|
||||||
|
Set<String> columnKeySet = hashTable.columnKeySet();
|
||||||
|
System.out.println("\nTable Column key 集合: " + columnKeySet);
|
||||||
|
|
||||||
|
// 获取值集合
|
||||||
|
Collection<Integer> values = hashTable.values();
|
||||||
|
System.out.println("\nTable 值集合: " + values);
|
||||||
|
|
||||||
|
// 判断包含行
|
||||||
|
boolean containsRow = hashTable.containsRow("xx公司");
|
||||||
|
System.out.println("\nTable 包含行: " + containsRow);
|
||||||
|
|
||||||
|
// 判断包含列
|
||||||
|
boolean containsColumn = hashTable.containsColumn("A部门");
|
||||||
|
System.out.println("\nTable 包含列: " + containsColumn);
|
||||||
|
|
||||||
|
// 判断包含行和列
|
||||||
|
boolean contains = hashTable.contains("xx公司", "A部门");
|
||||||
|
System.out.println("\nTable 包含行和列: " + contains);
|
||||||
|
|
||||||
|
// 判断包含值
|
||||||
|
boolean containsValue = hashTable.containsValue(10);
|
||||||
|
System.out.println("\nTable 包含值: " + containsValue);
|
||||||
|
|
||||||
|
// 行和列转置 - 行 转 列
|
||||||
|
Table<String, String, Integer> transposeTable = Tables.transpose(hashTable);
|
||||||
|
|
||||||
|
// 获取所有的行
|
||||||
|
Set<Table.Cell<String, String, Integer>> cells = transposeTable.cellSet();
|
||||||
|
|
||||||
|
// 遍历输出
|
||||||
|
System.out.println("\n遍历输出开始----------------------------");
|
||||||
|
cells.forEach(cell -> System.out.println(cell.getRowKey() + ", " + cell.getColumnKey() + ", " + cell.getValue()));
|
||||||
|
System.out.println("\n遍历输出结束----------------------------");
|
||||||
|
|
||||||
|
// 转换为嵌套的Map
|
||||||
|
Map<String, Map<String, Integer>> rowMap = hashTable.rowMap();
|
||||||
|
System.out.println("\nTable RowMap: " + rowMap);
|
||||||
|
Map<String, Map<String, Integer>> columnMap = hashTable.columnMap();
|
||||||
|
System.out.println("\nTable ColumnMap: " + columnMap);
|
||||||
|
```
|
||||||
|
|
||||||
|
执行结果:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
CopyHashMap 获取值: 10
|
||||||
|
|
||||||
|
Hash Table: {xx公司={A部门=10, B部门=20, C部门=30}}
|
||||||
|
|
||||||
|
Tree Table: {xx公司={A部门=10, B部门=20, C部门=30}}
|
||||||
|
|
||||||
|
Immutable Table: {xx公司={C部门=30, B部门=20, A部门=10}}
|
||||||
|
|
||||||
|
Table 获取值: 10
|
||||||
|
|
||||||
|
Table 删除值: 30
|
||||||
|
|
||||||
|
Table 列和值 映射: {A部门=10, B部门=20}
|
||||||
|
|
||||||
|
Table 行和值 映射: {xx公司=10}
|
||||||
|
|
||||||
|
Table Row key 集合: [xx公司]
|
||||||
|
|
||||||
|
Table Column key 集合: [A部门, B部门]
|
||||||
|
|
||||||
|
Table 值集合: [10, 20]
|
||||||
|
|
||||||
|
Table 包含行: true
|
||||||
|
|
||||||
|
Table 包含列: true
|
||||||
|
|
||||||
|
Table 包含行和列: true
|
||||||
|
|
||||||
|
Table 包含值: true
|
||||||
|
|
||||||
|
遍历输出开始----------------------------
|
||||||
|
A部门, xx公司, 10
|
||||||
|
B部门, xx公司, 20
|
||||||
|
|
||||||
|
遍历输出结束----------------------------
|
||||||
|
|
||||||
|
Table RowMap: {xx公司={A部门=10, B部门=20}}
|
||||||
|
|
||||||
|
Table ColumnMap: {A部门={xx公司=10}, B部门={xx公司=20}}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4. BiMap - 双向映射Map[#](https://www.cnblogs.com/cao-lei/p/17806222.html#2347438548)
|
||||||
|
|
||||||
|
官方注释翻译:双映射(或“双向映射”)是一种保留其值及其键的唯一性的映射。此约束使双映射能够支持“反向视图”,即另一个双映射,其中包含与此双映射相同的条目,但具有相反的键和值。
|
||||||
|
示例代码(需求: 数组和英文翻译):
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
Copy// 创建BiMap, 底层为两个Hash表的Map
|
||||||
|
BiMap<Integer, String> biMap = HashBiMap.create();
|
||||||
|
biMap.put(1, "one");
|
||||||
|
biMap.put(2, "two");
|
||||||
|
biMap.put(3, "three");
|
||||||
|
biMap.put(4, "four");
|
||||||
|
biMap.put(5, "five");
|
||||||
|
|
||||||
|
System.out.println("BiMap: " + biMap);
|
||||||
|
|
||||||
|
// 创建不可变BiMap, 无法新增、更新或删除
|
||||||
|
BiMap<Object, Object> immutableBiMap = ImmutableBiMap.builder()
|
||||||
|
.put(1, "one")
|
||||||
|
.put(2, "two")
|
||||||
|
.put(3, "three")
|
||||||
|
.put(4, "four")
|
||||||
|
.put(5, "five")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
System.out.println("\nImmutable BiMap: " + immutableBiMap);
|
||||||
|
|
||||||
|
// 通过key获取value
|
||||||
|
String value = biMap.get(1);
|
||||||
|
System.out.println("\nBiMap 根据key获取value: " + value);
|
||||||
|
|
||||||
|
Integer key = biMap.inverse().get("one");
|
||||||
|
System.out.println("\nBiMap 根据value获取key: " + key);
|
||||||
|
|
||||||
|
// 翻转后修改
|
||||||
|
biMap.inverse().put("six", 6);
|
||||||
|
// 返回双映射的逆视图, 并没有创建新对象, 还是之前的对象, 所以操作翻转后的BiMap会影响之前的BiMap
|
||||||
|
System.out.println("\nBiMap 被影响: " + biMap);
|
||||||
|
|
||||||
|
// 底层是HashMap, key不可重复
|
||||||
|
// value不可重复
|
||||||
|
try {
|
||||||
|
biMap.put(11, "one");
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("BiMap 替换value异常: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 翻转后key不能重复
|
||||||
|
try {
|
||||||
|
biMap.inverse().put("first", 1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.err.println("BiMap 替换key异常: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// key和value可为null
|
||||||
|
biMap.put(null, null);
|
||||||
|
System.out.println("\nBiMap 根据Null key获取Null value: " + biMap.get(null));
|
||||||
|
System.out.println("\nBiMap 根据Null value获取Null key: " + biMap.inverse().get(null));
|
||||||
|
|
||||||
|
// 强制替换key
|
||||||
|
biMap.forcePut(11, "one");
|
||||||
|
System.out.println("\nBiMap 获取新key: " + biMap.inverse().get("one"));
|
||||||
|
|
||||||
|
// values为Set集合
|
||||||
|
Set<String> values = biMap.values();
|
||||||
|
System.out.println("\nBiMap 不重复的value: " + values);
|
||||||
|
```
|
||||||
|
|
||||||
|
执行结果:
|
||||||
|
|
||||||
|
```mipsasm
|
||||||
|
CopyBiMap: {1=one, 2=two, 3=three, 4=four, 5=five}
|
||||||
|
|
||||||
|
Immutable BiMap: {1=one, 2=two, 3=three, 4=four, 5=five}
|
||||||
|
|
||||||
|
BiMap 根据key获取value: one
|
||||||
|
|
||||||
|
BiMap 根据value获取key: 1
|
||||||
|
|
||||||
|
BiMap 被影响: {1=one, 2=two, 3=three, 4=four, 5=five, 6=six}
|
||||||
|
BiMap 替换value异常: value already present: one
|
||||||
|
BiMap 替换key异常: key already present: 1
|
||||||
|
|
||||||
|
BiMap 根据Null key获取Null value: null
|
||||||
|
|
||||||
|
BiMap 根据Null value获取Null key: null
|
||||||
|
|
||||||
|
BiMap 获取新key: 11
|
||||||
|
|
||||||
|
BiMap 不重复的value: [two, three, four, five, six, null, one]
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 5. Multimap - 多重映射Map[#](https://www.cnblogs.com/cao-lei/p/17806222.html#819077997)
|
||||||
|
|
||||||
|
官方注释翻译将键映射到值的集合,类似于 Map,但其中每个键可能与 多个 值相关联。
|
||||||
|
示例代码(需求: 学生和各科选修课成绩):
|
||||||
|
|
||||||
|
```swift
|
||||||
|
Copy// 创建Multimap, key为HashMap, value为ArrayList
|
||||||
|
Multimap<String, Integer> arrayListMultimap = ArrayListMultimap.create();
|
||||||
|
arrayListMultimap.put("张三", 90);
|
||||||
|
arrayListMultimap.put("张三", 80);
|
||||||
|
arrayListMultimap.put("张三", 100);
|
||||||
|
arrayListMultimap.put("李四", 88);
|
||||||
|
|
||||||
|
System.out.println("Multimap key为HashMap, value为ArrayList: " + arrayListMultimap);
|
||||||
|
|
||||||
|
// 创建Multimap, key为HashMap, value为HashSet
|
||||||
|
Multimap<String, Integer> hashMultimap = HashMultimap.create();
|
||||||
|
hashMultimap.put("张三", 90);
|
||||||
|
hashMultimap.put("张三", 80);
|
||||||
|
hashMultimap.put("张三", 100);
|
||||||
|
hashMultimap.put("李四", 88);
|
||||||
|
|
||||||
|
System.out.println("\nMultimap key为HashMap, value为HashSet: " + hashMultimap);
|
||||||
|
|
||||||
|
// 创建Multimap, key为LinkedHashMap, value为LinkedList
|
||||||
|
Multimap<String, Integer> linkedListMultimap = LinkedListMultimap.create();
|
||||||
|
linkedListMultimap.put("张三", 90);
|
||||||
|
linkedListMultimap.put("张三", 80);
|
||||||
|
linkedListMultimap.put("张三", 100);
|
||||||
|
linkedListMultimap.put("李四", 88);
|
||||||
|
|
||||||
|
System.out.println("\nMultimap key为LinkedHashMap, value为LinkedList: " + linkedListMultimap);
|
||||||
|
|
||||||
|
// 创建Multimap, key为LinkedHashMap, value为LinkedHashMap
|
||||||
|
Multimap<String, Integer> linkedHashMultimap = LinkedHashMultimap.create();
|
||||||
|
linkedHashMultimap.put("张三", 90);
|
||||||
|
linkedHashMultimap.put("张三", 80);
|
||||||
|
linkedHashMultimap.put("张三", 100);
|
||||||
|
linkedHashMultimap.put("李四", 88);
|
||||||
|
|
||||||
|
System.out.println("\nMultimap key为LinkedHashMap, value为LinkedHashMap: " + linkedHashMultimap);
|
||||||
|
|
||||||
|
// 创建Multimap, key为TreeMap, value为TreeSet
|
||||||
|
Multimap<String, Integer> treeMultimap = TreeMultimap.create();
|
||||||
|
treeMultimap.put("张三", 90);
|
||||||
|
treeMultimap.put("张三", 80);
|
||||||
|
treeMultimap.put("张三", 100);
|
||||||
|
treeMultimap.put("李四", 88);
|
||||||
|
|
||||||
|
System.out.println("\nMultimap key为TreeMap, value为TreeSet: " + treeMultimap);
|
||||||
|
|
||||||
|
// 创建不可变Multimap, 无法新增、更新或删除, key为ImmutableMap, value为ImmutableList
|
||||||
|
Multimap<String, Integer> immutableListMultimap = ImmutableListMultimap.<String, Integer>builder()
|
||||||
|
.put("张三", 90)
|
||||||
|
.put("张三", 80)
|
||||||
|
.put("张三", 100)
|
||||||
|
.put("李四", 88)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
System.out.println("\nMultimap key为ImmutableMap, value为ImmutableList: " + immutableListMultimap);
|
||||||
|
|
||||||
|
// 创建不可变Multimap, 无法新增、更新或删除, key为ImmutableMap, value为ImmutableSet
|
||||||
|
Multimap<String, Integer> immutableSetMultimap = ImmutableSetMultimap.<String, Integer>builder()
|
||||||
|
.put("张三", 90)
|
||||||
|
.put("张三", 80)
|
||||||
|
.put("张三", 100)
|
||||||
|
.put("李四", 88)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
System.out.println("\nMultimap key为ImmutableMap, value为ImmutableSet: " + immutableSetMultimap);
|
||||||
|
|
||||||
|
// 获取值
|
||||||
|
Collection<Integer> values = arrayListMultimap.get("张三");
|
||||||
|
System.out.println("\nMultimap 获取值集合: " + values);
|
||||||
|
|
||||||
|
// 获取不存在key的值, 返回的是空集合, 而不是null
|
||||||
|
Collection<Integer> valuesByNotExistsKey = arrayListMultimap.get("王五");
|
||||||
|
System.out.println("\nMultimap 获取不存在的Key值集合: " + valuesByNotExistsKey);
|
||||||
|
|
||||||
|
// 获取值集合添加值
|
||||||
|
// 返回的是多重映射中关联的值的视图集合, 并没有创建新对象, 还是之前的对象, 所以操作值集合会影响之前的Multimap
|
||||||
|
values.add(60);
|
||||||
|
System.out.println("\nMultimap 被影响: " + arrayListMultimap);
|
||||||
|
|
||||||
|
// 获取大小
|
||||||
|
System.out.println("\nMultimap 大小:" + arrayListMultimap.size());
|
||||||
|
|
||||||
|
// 判断是否为空
|
||||||
|
System.out.println("\nMultimap 是否为空: " + arrayListMultimap.isEmpty());
|
||||||
|
|
||||||
|
// 包含key
|
||||||
|
System.out.println("\nMultimap 包含key: " + arrayListMultimap.containsKey("张三"));
|
||||||
|
|
||||||
|
// 包含value
|
||||||
|
System.out.println("\nMultimap 包含value: " + arrayListMultimap.containsValue(60));
|
||||||
|
|
||||||
|
// 包含key-value键值对
|
||||||
|
System.out.println("\nMultimap 包含key-value对: " + arrayListMultimap.containsEntry("张三", 60));
|
||||||
|
|
||||||
|
// 替换value
|
||||||
|
arrayListMultimap.replaceValues("张三", Arrays.asList(10, 20, 30));
|
||||||
|
System.out.println("\nMultimap 替换value: " + arrayListMultimap);
|
||||||
|
|
||||||
|
// 根据key-value删除
|
||||||
|
arrayListMultimap.remove("张三", 10);
|
||||||
|
System.out.println("\nMultimap 根据key-value删除: " + arrayListMultimap);
|
||||||
|
|
||||||
|
// 根据key删除
|
||||||
|
Collection<Integer> removeAll = arrayListMultimap.removeAll("张三");
|
||||||
|
System.out.println("\nMultimap 根据key删除: " + removeAll);
|
||||||
|
|
||||||
|
// 获取key集合
|
||||||
|
Set<String> keySet = arrayListMultimap.keySet();
|
||||||
|
System.out.println("\nMultimap 获取key集合(HashSet): " + keySet);
|
||||||
|
Multiset<String> keys = arrayListMultimap.keys();
|
||||||
|
System.out.println("\nMultimap 获取key集合(MultiSet): " + keys);
|
||||||
|
|
||||||
|
// 获取所有的key-value
|
||||||
|
Collection<Map.Entry<String, Integer>> entries = arrayListMultimap.entries();
|
||||||
|
System.out.println("\n遍历key-value开始--------------------------");
|
||||||
|
entries.forEach(entry -> System.out.println(entry.getKey() + " : " + entry.getValue()));
|
||||||
|
System.out.println("\n遍历key-value结束--------------------------");
|
||||||
|
|
||||||
|
// 转换为Map<K, Collection<V>>
|
||||||
|
Map<String, Collection<Integer>> collectionMap = arrayListMultimap.asMap();
|
||||||
|
System.out.println("\nMultimap 转换为Map<K, Collection<V>>: " + collectionMap);
|
||||||
|
```
|
||||||
|
|
||||||
|
执行结果:
|
||||||
|
|
||||||
|
```mipsasm
|
||||||
|
CopyMultimap key为HashMap, value为ArrayList: {李四=[88], 张三=[90, 80, 100]}
|
||||||
|
|
||||||
|
Multimap key为HashMap, value为HashSet: {李四=[88], 张三=[80, 100, 90]}
|
||||||
|
|
||||||
|
Multimap key为LinkedHashMap, value为LinkedList: {张三=[90, 80, 100], 李四=[88]}
|
||||||
|
|
||||||
|
Multimap key为LinkedHashMap, value为LinkedHashMap: {张三=[90, 80, 100], 李四=[88]}
|
||||||
|
|
||||||
|
Multimap key为TreeMap, value为TreeSet: {张三=[80, 90, 100], 李四=[88]}
|
||||||
|
|
||||||
|
Multimap key为ImmutableMap, value为ImmutableList: {张三=[90, 80, 100], 李四=[88]}
|
||||||
|
|
||||||
|
Multimap key为ImmutableMap, value为ImmutableSet: {张三=[90, 80, 100], 李四=[88]}
|
||||||
|
|
||||||
|
Multimap 获取值集合: [90, 80, 100]
|
||||||
|
|
||||||
|
Multimap 获取不存在的Key值集合: []
|
||||||
|
|
||||||
|
Multimap 被影响: {李四=[88], 张三=[90, 80, 100, 60]}
|
||||||
|
|
||||||
|
Multimap 大小:5
|
||||||
|
|
||||||
|
Multimap 是否为空: false
|
||||||
|
|
||||||
|
Multimap 包含key: true
|
||||||
|
|
||||||
|
Multimap 包含value: true
|
||||||
|
|
||||||
|
Multimap 包含key-value对: true
|
||||||
|
|
||||||
|
Multimap 替换value: {李四=[88], 张三=[10, 20, 30]}
|
||||||
|
|
||||||
|
Multimap 根据key-value删除: {李四=[88], 张三=[20, 30]}
|
||||||
|
|
||||||
|
Multimap 根据key删除: [20, 30]
|
||||||
|
|
||||||
|
Multimap 获取key集合(HashSet): [李四]
|
||||||
|
|
||||||
|
Multimap 获取key集合(MultiSet): [李四]
|
||||||
|
|
||||||
|
遍历key-value开始--------------------------
|
||||||
|
李四 : 88
|
||||||
|
|
||||||
|
遍历key-value结束--------------------------
|
||||||
|
|
||||||
|
Multimap 转换为Map<K, Collection<V>>: {李四=[88]}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 6. RangeMap - 范围映射Map[#](https://www.cnblogs.com/cao-lei/p/17806222.html#684335507)
|
||||||
|
|
||||||
|
官方注释翻译:从不相交的非空范围到非 null 值的映射。查询查找与包含指定键的范围(如果有)关联的值。
|
||||||
|
示例代码(需求:考试成绩分类):
|
||||||
|
|
||||||
|
```swift
|
||||||
|
Copy// if-else
|
||||||
|
int score = 88;
|
||||||
|
String rank;
|
||||||
|
if (0 <= score && score < 60) {
|
||||||
|
rank = "不及格";
|
||||||
|
} else if (60 <= score && score <= 84) {
|
||||||
|
rank = "及格";
|
||||||
|
} else if (84 < score && score <= 100) {
|
||||||
|
rank = "优秀";
|
||||||
|
} else {
|
||||||
|
rank = "无效";
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("if-else 获取值: " + rank);
|
||||||
|
|
||||||
|
// 创建RangeMap, 基于TreeMap(红黑树)实现
|
||||||
|
RangeMap<Integer, String> treeRangeMap = TreeRangeMap.create();
|
||||||
|
treeRangeMap.put(Range.closedOpen(0, 60), "不及格");
|
||||||
|
treeRangeMap.put(Range.closed(60, 84), "及格");
|
||||||
|
treeRangeMap.put(Range.openClosed(84, 100), "优秀");
|
||||||
|
treeRangeMap.put(Range.lessThan(0), "无效");
|
||||||
|
treeRangeMap.put(Range.greaterThan(100), "无效");
|
||||||
|
|
||||||
|
rank = treeRangeMap.get(score);
|
||||||
|
System.out.println("\nRangeMap 获取值: " + rank);
|
||||||
|
|
||||||
|
// 创建不可变RangeMap, 无法新增、更新或删除
|
||||||
|
ImmutableRangeMap<Integer, String> immutableRangeMap = ImmutableRangeMap.<Integer, String>builder()
|
||||||
|
.put(Range.closedOpen(0, 60), "不及格")
|
||||||
|
.put(Range.closed(60, 84), "及格")
|
||||||
|
.put(Range.openClosed(84, 100), "优秀")
|
||||||
|
.put(Range.lessThan(0), "无效")
|
||||||
|
.put(Range.greaterThan(100), "无效")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
rank = immutableRangeMap.get(score);
|
||||||
|
System.out.println("\nImmutableRangeMap 获取值: " + rank);
|
||||||
|
|
||||||
|
// 获取key-value对
|
||||||
|
Map.Entry<Range<Integer>, String> entry = treeRangeMap.getEntry(88);
|
||||||
|
System.out.println("\nRangeMap 获取key-value对: " + entry.getKey() + " : " + entry.getValue());
|
||||||
|
|
||||||
|
// 返回不可变的升序的Map
|
||||||
|
Map<Range<Integer>, String> asMapOfRanges = treeRangeMap.asMapOfRanges();
|
||||||
|
System.out.println("\nRangeMap 不可变的升序的Map: " + asMapOfRanges);
|
||||||
|
|
||||||
|
// 返回不可变的降序的Map
|
||||||
|
Map<Range<Integer>, String> asDescendingMapOfRanges = treeRangeMap.asDescendingMapOfRanges();
|
||||||
|
System.out.println("\nRangeMap 不可变的降序的Map: " + asDescendingMapOfRanges);
|
||||||
|
|
||||||
|
// 相连范围合并
|
||||||
|
RangeMap<Integer, String> treeRangeMap2 = TreeRangeMap.create();
|
||||||
|
treeRangeMap2.putCoalescing(Range.closedOpen(0, 60), "不及格");
|
||||||
|
treeRangeMap2.putCoalescing(Range.closed(60, 84), "及格");
|
||||||
|
treeRangeMap2.putCoalescing(Range.openClosed(84, 100), "及格"); // 或者 [60..84]范围合并
|
||||||
|
treeRangeMap2.putCoalescing(Range.lessThan(0), "无效");
|
||||||
|
treeRangeMap2.putCoalescing(Range.greaterThan(100), "无效");
|
||||||
|
System.out.println("\nRangeMap 不合并相连范围: " + treeRangeMap.asMapOfRanges());
|
||||||
|
System.out.println("RangeMap 合并相连范围: " + treeRangeMap2.asMapOfRanges());
|
||||||
|
|
||||||
|
// 最小范围
|
||||||
|
Range<Integer> span = treeRangeMap.span();
|
||||||
|
System.out.println("\nRangeMap 最小范围: " + span);
|
||||||
|
|
||||||
|
// 子范围Map
|
||||||
|
RangeMap<Integer, String> subRangeMap = treeRangeMap.subRangeMap(Range.closed(70, 90));
|
||||||
|
System.out.println("\nRangeMap 子范围Map: " + subRangeMap);
|
||||||
|
|
||||||
|
// 合并范围
|
||||||
|
treeRangeMap.merge(Range.closed(60, 100), "及格", (s, s2) -> s2);
|
||||||
|
System.out.println("\nRangeMap 合并Map: " + treeRangeMap);
|
||||||
|
|
||||||
|
// 移除范围
|
||||||
|
treeRangeMap.remove(Range.open(90, 95));
|
||||||
|
System.out.println("\nRangeMap 移除范围: " + treeRangeMap);
|
||||||
|
|
||||||
|
// 清除所有范围
|
||||||
|
treeRangeMap.clear();
|
||||||
|
System.out.println("\nRangeMap 清除所有范围: " + treeRangeMap);
|
||||||
|
```
|
||||||
|
|
||||||
|
执行结果:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
Copyif-else 获取值: 优秀
|
||||||
|
|
||||||
|
RangeMap 获取值: 优秀
|
||||||
|
|
||||||
|
ImmutableRangeMap 获取值: 优秀
|
||||||
|
|
||||||
|
RangeMap 获取key-value对: (84..100] : 优秀
|
||||||
|
|
||||||
|
RangeMap 不可变的升序的Map: {(-∞..0)=无效, [0..60)=不及格, [60..84]=及格, (84..100]=优秀, (100..+∞)=无效}
|
||||||
|
|
||||||
|
RangeMap 不可变的降序的Map: {(100..+∞)=无效, (84..100]=优秀, [60..84]=及格, [0..60)=不及格, (-∞..0)=无效}
|
||||||
|
|
||||||
|
RangeMap 不合并相连范围: {(-∞..0)=无效, [0..60)=不及格, [60..84]=及格, (84..100]=优秀, (100..+∞)=无效}
|
||||||
|
RangeMap 合并相连范围: {(-∞..0)=无效, [0..60)=不及格, [60..100]=及格, (100..+∞)=无效}
|
||||||
|
|
||||||
|
RangeMap 最小范围: (-∞..+∞)
|
||||||
|
|
||||||
|
RangeMap 子范围Map: {[70..84]=及格, (84..90]=优秀}
|
||||||
|
|
||||||
|
RangeMap 合并Map: [(-∞..0)=无效, [0..60)=不及格, [60..84]=及格, (84..100]=及格, (100..+∞)=无效]
|
||||||
|
|
||||||
|
RangeMap 移除范围: [(-∞..0)=无效, [0..60)=不及格, [60..84]=及格, (84..90]=及格, [95..100]=及格, (100..+∞)=无效]
|
||||||
|
|
||||||
|
RangeMap 清除所有范围: []
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 7. ClassToInstanceMap - 类型映射到实例Map[#](https://www.cnblogs.com/cao-lei/p/17806222.html#85873049)
|
||||||
|
|
||||||
|
官方注释翻译:映射,其每个条目将一个 Java 原始类型 映射到该类型的实例。除了实现 Map之外,还提供额外的类型安全操作 putInstance 和 getInstance 。与任何其他 Map<Class, Object>映射一样,此映射可能包含基元类型的条目,并且基元类型及其相应的包装器类型可以映射到不同的值。
|
||||||
|
示例代码(需求:缓存Bean(不交给Spring管理,自己管理Bean)):
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
Copyclass UserBean {
|
||||||
|
private final Integer id;
|
||||||
|
private final String username;
|
||||||
|
|
||||||
|
public UserBean(Integer id, String username) {
|
||||||
|
this.id = id;
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "UserBean{" + "id=" + id + ", username='" + username + '\'' + '}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 创建Bean
|
||||||
|
UserBean userBean = new UserBean(1, "张三");
|
||||||
|
|
||||||
|
// HashMap
|
||||||
|
HashMap<Class, Object> hashMap = new HashMap<>();
|
||||||
|
hashMap.put(UserBean.class, userBean);
|
||||||
|
|
||||||
|
// 获取值,需要强转
|
||||||
|
UserBean value = (UserBean) hashMap.get(UserBean.class);
|
||||||
|
System.out.println("HashMap 获取对象实例: " + value);
|
||||||
|
System.out.println("HashMap 获取对象实例等于创建的Bean: " + (value == userBean));
|
||||||
|
|
||||||
|
// 创建ClassToInstanceMap
|
||||||
|
ClassToInstanceMap<Object> classToInstanceMap = MutableClassToInstanceMap.create();
|
||||||
|
classToInstanceMap.putInstance(UserBean.class, userBean);
|
||||||
|
|
||||||
|
// 获取值,无需强转
|
||||||
|
UserBean value2 = classToInstanceMap.getInstance(UserBean.class);
|
||||||
|
System.out.println("\nClassToInstanceMap 获取对象实例: " + value2);
|
||||||
|
System.out.println("ClassToInstanceMap 获取对象实例等于创建的Bean: " + (value2 == userBean));
|
||||||
|
|
||||||
|
// 创建不可变ClassToInstanceMap, 无法新增、更新或删除
|
||||||
|
ClassToInstanceMap<UserBean> immutableClassToInstanceMap = ImmutableClassToInstanceMap.<UserBean>builder()
|
||||||
|
.put(UserBean.class, userBean)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 获取值,无需强转
|
||||||
|
UserBean value3 = immutableClassToInstanceMap.getInstance(UserBean.class);
|
||||||
|
System.out.println("\nImmutableClassToInstanceMap 获取对象实例: " + value3);
|
||||||
|
System.out.println("ImmutableClassToInstanceMap 获取对象实例等于创建的Bean: " + (value3 == userBean));
|
||||||
|
|
||||||
|
|
||||||
|
// 限制类型,避免使用HashMap存储对象时,因为使用Object值类型而在添加缓存时需要今天类型校验
|
||||||
|
ClassToInstanceMap<Collection> classToInstanceMap1 = MutableClassToInstanceMap.create();
|
||||||
|
classToInstanceMap1.put(ArrayList.class, new ArrayList());
|
||||||
|
classToInstanceMap1.put(HashSet.class, new HashSet());
|
||||||
|
// 编译保存: 'put(java.lang.Class<? extends java.util.@org.checkerframework.checker.nullness.qual.NonNull Collection>, java.util.Collection)' in 'com.google.common.collect.MutableClassToInstanceMap' cannot be applied to '(java.lang.Class<java.util.HashMap>, java.util.HashMap)'
|
||||||
|
// classToInstanceMap1.put(HashMap.class, new HashMap());
|
||||||
|
```
|
||||||
|
|
||||||
|
执行结果:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
CopyHashMap 获取对象实例: UserBean{id=1, username='张三'}
|
||||||
|
HashMap 获取对象实例等于创建的Bean: true
|
||||||
|
|
||||||
|
ClassToInstanceMap 获取对象实例: UserBean{id=1, username='张三'}
|
||||||
|
ClassToInstanceMap 获取对象实例等于创建的Bean: true
|
||||||
|
|
||||||
|
ImmutableClassToInstanceMap 获取对象实例: UserBean{id=1, username='张三'}
|
||||||
|
ImmutableClassToInstanceMap 获取对象实例等于创建的Bean: true
|
||||||
|
```
|
10
java/mybatis-plus.md
Normal file
10
java/mybatis-plus.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
### mybtais-plus
|
||||||
|
|
||||||
|
mybtais-plus 默认空字段 不插入 导致生成的sql 字段不完整,
|
||||||
|
|
||||||
|
在批量插入时, 因为每个po 空值不确定 导致 sql 重写失效,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
&reWriteBatchedInserts=true
|
29
openwrt/openVPN.md
Normal file
29
openwrt/openVPN.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
## openWrt 路由器中的 openVPN 组件
|
||||||
|
|
||||||
|
| **连接类型** | 配置文件说明 | **模式** | **网络类型** | **适用场景** | **对应配置文件示例** |
|
||||||
|
| :-------------------- | ----------------------------------------------------------- | :------- | :---------------- | :----------------------------------------------------------- | :------------------- |
|
||||||
|
| **client_tap_bridge** | Client configuration for an ethernet bridge VPN | 客户端 | TAP(以太网桥接) | 客户端需完全接入服务器局域网(如访问 SMB 共享、网络打印机等) | `client-bridge.conf` |
|
||||||
|
| **client_tun** | Client configuration for a routed multi-client VPN | 客户端 | TUN(IP 路由) | 标准多客户端 VPN,适用于远程办公、访问内网服务 | `client-routed.conf` |
|
||||||
|
| **client_tun_ptp** | Simple client configuration for a routed point-to-point VPN | 客户端 | TUN(点对点路由) | 仅 1 对 1 连接,适合设备间专用加密隧道(如远程管理) | `client-p2p.conf` |
|
||||||
|
| **server_tap_bridge** | Server configuration for an ethernet bridge VPN | 服务器 | TAP(以太网桥接) | 服务器提供桥接模式 VPN,客户端像本地设备一样访问整个 LAN | `server-bridge.conf` |
|
||||||
|
| **server_tun** | Server configuration for a routed multi-client VPN | 服务器 | TUN(IP 路由) | 标准多客户端 VPN 服务器,适用于企业远程访问 | `server-routed.conf` |
|
||||||
|
| **server_tun_ptp** | Simple server configuration for a routed point-to-point VPN | 服务器 | TUN(点对点路由) | 仅支持 1 对 1 连接的 VPN 服务器(如站点间 VPN) | `server-p2p.conf` |
|
||||||
|
|
||||||
|
### **关键说明**:
|
||||||
|
|
||||||
|
1. **配置文件名**:
|
||||||
|
- 通常 OpenVPN 会根据 `option value` 生成对应的配置文件(如 `client_tun` → `client-routed.conf`)。
|
||||||
|
- 实际文件名可能因系统不同有所变化,但逻辑一致。
|
||||||
|
2. **TAP vs. TUN**:
|
||||||
|
- **TAP(`tap_bridge`)**:模拟以太网设备,适合需要广播/组播的应用(如网络游戏、局域网发现)。
|
||||||
|
- **TUN(`tun`)**:仅路由 IP 流量,更高效,适合大多数 VPN(如网页访问、SSH)。
|
||||||
|
3. **多客户端 vs. 点对点(P2P)**:
|
||||||
|
- **普通模式(`server_tun`/`client_tun`)**:支持多个客户端同时连接。
|
||||||
|
- **点对点(`_ptp`)**:仅限两个节点直接通信,延迟更低。
|
||||||
|
|
||||||
|
### **典型应用**:
|
||||||
|
|
||||||
|
- **企业远程办公** → `server_tun` + `client_tun`
|
||||||
|
- **家庭局域网扩展** → `server_tap_bridge` + `client_tap_bridge`
|
||||||
|
- **服务器间加密通道** → `server_tun_ptp` + `client_tun_ptp`
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user