支持多键查询且不允许重复键的Java数据结构及第三方库选型咨询
解决方案
你的核心需求是两个独立唯一键索引、支持任意键查询、重复键插入拦截,现有通用数据结构没有完全匹配的开箱即用实现,推荐两种实现方式:
方案1:轻量自定义封装(推荐,无额外依赖、完全匹配需求)
基于两个HashMap分别维护PIN到车辆、驾驶证号到车辆的映射,插入时做双维度唯一校验,实现代码如下:
import java.util.HashMap; import java.util.Map; import java.util.Optional; public class DualUniqueKeyStore<V> { private final Map<String, V> pinIndex = new HashMap<>(); private final Map<String, V> licenseIndex = new HashMap<>(); public synchronized void add(String pin, String driverLicense, V value) { // 校验两个键的唯一性 if (pinIndex.containsKey(pin)) { throw new IllegalArgumentException("PIN " + pin + " 已被分配"); } if (licenseIndex.containsKey(driverLicense)) { throw new IllegalArgumentException("驾驶证号 " + driverLicense + " 已被分配"); } pinIndex.put(pin, value); licenseIndex.put(driverLicense, value); } public Optional<V> getByPin(String pin) { return Optional.ofNullable(pinIndex.get(pin)); } public Optional<V> getByDriverLicense(String driverLicense) { return Optional.ofNullable(licenseIndex.get(driverLicense)); } // 按需添加删除、清空等方法即可 }
用法示例
刚好匹配你预期的调用逻辑:
// 车辆枚举定义略 DualUniqueKeyStore<Car> store = new DualUniqueKeyStore<>(); store.add("pin-1", "driverLicense-1", Car.TOYOTA); store.add("pin-2", "driverLicense-2", Car.FORD); store.add("pin-1", "driverLicense-3", Car.FORD); // 抛出异常:PIN pin-1 已被分配
如果不需要线程安全,可以去掉add方法的synchronized关键字提升性能。
方案2:基于现有第三方库改造
如果你不想自己维护基础逻辑,也可以基于Guava的HashBasedTable做二次校验封装,插入前先判断行(PIN)和列(驾驶证号)是否已存在,存在就抛出异常:
import com.google.common.collect.HashBasedTable; import com.google.common.collect.Table; public class UniqueKeyTable<V> { private final Table<String, String, V> table = HashBasedTable.create(); public synchronized void add(String pin, String driverLicense, V value) { if (table.containsRow(pin)) { throw new IllegalArgumentException("PIN " + pin + " 已被分配"); } if (table.containsColumn(driverLicense)) { throw new IllegalArgumentException("驾驶证号 " + driverLicense + " 已被分配"); } table.put(pin, driverLicense, value); } // 对应封装查询方法即可 }
这种方式可以复用Table已有的批量查询、遍历等能力,适合需要更多复杂操作的场景。
为什么HashBasedTable原生不符合需求
HashBasedTable是行+列的组合索引,仅会在同一行+同一列重复插入时覆盖旧值,只要行或列任意一个不同就允许插入,和你要求的单维度键全局唯一的逻辑不符,所以必须加前置校验。
内容的提问来源于stack exchange,提问作者Jon
相关产品推荐
相关产品推荐

