关于Set —— 莫把Set与Map搞混淆
1.Set和Map的本质区别
数据结构 | 仅存储唯一的值 | 存储键值对 (key-value) |
是否成对 | ❌ 只存值,没有 key | ✅ 每个 value 都有对应的 key |
数据存储 | HashSet、TreeSet、LinkedHashSet | HashMap、TreeMap、LinkedHashMap |
查找性能 | 查找、添加、删除的效率为 O(1) (HashSet) | 查找、添加、删除的效率为 O(1) (HashMap) |
数据去重 | ✅ 自动去重 | ✅ Key 自动去重,Value 不去重 |
元素顺序 | ❌ 无序 (HashSet) | ❌ 无序 (HashMap) |
2.Set<String>的本质
✅ Set只存储值(Value),并不存储 key。
那为什么Set还能做到"唯一性"呢?
Set的底层实现利用了哈希表(HashSet)或树(TreeSet)的数据结构。
在HashSet中:
- 每个元素都会根据其哈希值 (Hash Code) 来定位存储位置。
- 在存储时,如果哈希值已存在,就不会再添加该元素,从而实现唯一性。
🚨关键点:Set并不需要显式地存储key,因为 HashSet 的底层机制就是将每个元素的哈希值作为其"定位点"(相当于隐形的key)。
3.Set的实际应用场景
尽管Set只有值,但在以下场景中非常实用:
✅ (1) 数据去重
当需要在一堆数据中提取唯一元素时,Set是最佳选择。
Set<String> uniqueNames = new HashSet<>(Arrays.asList("Alice", "Bob", "Alice", "Charlie")); System.out.println(uniqueNames); // 输出: [Alice, Bob, Charlie]
✅ (2) 快速查找
HashSet查找元素的速度远快于List,尤其在数据量较大时。
Set<String> codes = new HashSet<>(Arrays.asList("0100", "0251", "0252")); if (codes.contains("0100")) { System.out.println("找到编码0100"); }
✅ (3) 集合运算(交集、并集、差集)
Set提供了快速的集合运算支持:
Set<String> set1 = new HashSet<>(Arrays.asList("A", "B", "C")); Set<String> set2 = new HashSet<>(Arrays.asList("B", "C", "D")); // 求交集 set1.retainAll(set2); System.out.println(set1); // 输出: [B, C]
4. 为什么Set适合iscpSector这种编码集合?
在你的代码中:
private Set<String> iscpSector = new HashSet<>(Arrays.asList("0100", "0251", "0252", "0241", "0242", "0211", "0200"));
✅ 编码数据本身不需要 key,只需记录一组唯一值。
✅ Set能自动去重,避免因重复编码而出错。
✅ HashSet查找效率高,判断 "0100" 是否存在的效率远高于List。
5.如果需要key-value形式怎么办?
如果你的数据确实是成对的(即 key-value),应该使用Map,而不是Set。
示例:使用Map存储key-value
Map<String, String> serviceMap = new HashMap<>(); serviceMap.put("0100", "水运干线"); serviceMap.put("0251", "集港"); serviceMap.put("0252", "疏港");
✅ Set适合仅存储唯一值。
✅ Map适合存储key-value键值对。
6.总结
🔹 Set不存储key,它本质上只有value。
🔹 Set的“唯一性”是靠哈希值自动实现的,不需要显式的key。
🔹 在你的代码中,iscpSector只是一组编码,使用Set更合适。
🔹 如果你要存储的是 "编码 → 描述" 的形式(如 "0100" → "水运干线"),就应该使用 Map