自定义Index作为TreeMap键:按Date排序,通过Long id判断containsKey
实现按date排序、按id判断键存在的自定义Map
你的需求存在核心矛盾:TreeMap的键查找(containsKey、get)逻辑依赖其排序规则(Comparable或Comparator),但你要求排序用date、键存在性判断用id,这直接违反Java集合框架的契约(排序逻辑中相等的键必须视为同一个键)。你当前的Index类实现会导致TreeMap行为异常,比如相同date不同id的键会被视为重复,覆盖原有值。
可行方案:自定义包装Map
通过同时包装TreeMap和HashMap,分别实现排序和快速id查找的需求:
TreeMap负责按date排序存储键值对HashMap负责维护id到Index的映射,实现O(1)时间复杂度的存在性判断
1. 修正Index类(保证id作为唯一标识)
import java.util.Date; public class Index { public final Long id; public final Date date; public Index(Long id, Date date) { this.id = id; this.date = date; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Index index = (Index) o; return id.equals(index.id); } @Override public int hashCode() { return id.hashCode(); } }
2. 实现自定义包装Map
import java.util.*; public class IdKeySortedMap<V> implements Map<Index, V> { private final TreeMap<Index, V> sortedMap; private final HashMap<Long, Index> idIndexMap; public IdKeySortedMap() { // 按date升序排序 this.sortedMap = new TreeMap<>(Comparator.comparing(index -> index.date)); this.idIndexMap = new HashMap<>(); } @Override public V put(Index key, V value) { // 若id已存在,先移除旧键 Index existingKey = idIndexMap.get(key.id); if (existingKey != null) { sortedMap.remove(existingKey); } idIndexMap.put(key.id, key); return sortedMap.put(key, value); } // 支持直接传入Long类型的id判断存在性 public boolean containsKey(Long id) { return idIndexMap.containsKey(id); } @Override public boolean containsKey(Object key) { if (key instanceof Long) { return containsKey((Long) key); } if (key instanceof Index) { return idIndexMap.containsKey(((Index) key).id); } return false; } @Override public V get(Object key) { if (key instanceof Long) { Index indexKey = idIndexMap.get(key); return indexKey != null ? sortedMap.get(indexKey) : null; } return sortedMap.get(key); } // 委托其他Map接口方法给内部集合 @Override public int size() { return sortedMap.size(); } @Override public boolean isEmpty() { return sortedMap.isEmpty(); } @Override public boolean containsValue(Object value) { return sortedMap.containsValue(value); } @Override public void putAll(Map<? extends Index, ? extends V> m) { m.forEach(this::put); } @Override public V remove(Object key) { if (key instanceof Long) { Index indexKey = idIndexMap.remove(key); return indexKey != null ? sortedMap.remove(indexKey) : null; } if (key instanceof Index) { Index indexKey = (Index) key; idIndexMap.remove(indexKey.id); return sortedMap.remove(indexKey); } return null; } @Override public void clear() { sortedMap.clear(); idIndexMap.clear(); } @Override public Set<Index> keySet() { return Collections.unmodifiableSet(sortedMap.keySet()); } @Override public Collection<V> values() { return sortedMap.values(); } @Override public Set<Entry<Index, V>> entrySet() { return Collections.unmodifiableSet(sortedMap.entrySet()); } }
3. 测试代码
import java.text.SimpleDateFormat; import java.util.Date; public class TestDemo { public static void main(String[] args) throws Exception { SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm"); IdKeySortedMap<Object> items = new IdKeySortedMap<>(); items.put(new Index(10L, formatter.parse("2023-03-14 10:00")), 10L); items.put(new Index(20L, formatter.parse("2023-03-14 08:00")), 20L); // 验证需求1:检测id存在性 System.out.println(items.containsKey(10L)); // 输出true System.out.println(items.containsKey(30L)); // 输出false // 验证需求3:按date排序输出 for (Map.Entry<Index, Object> entry : items.entrySet()) { System.out.printf("id:%d, date:%s%n", entry.getKey().id, formatter.format(entry.getKey().date)); // 输出顺序:id:20, date:2023-03-14 08:00 → id:10, date:2023-03-14 10:00 } // 验证需求2:重复id的put会替换旧值 items.put(new Index(10L, formatter.parse("2023-03-15 09:00")), 100L); System.out.println(items.get(10L)); // 输出100L } }
方案说明
- 完全满足你的三个需求:支持
containsKey(Long)判断id存在性,put可正常添加/替换键值对,遍历顺序按date升序排列。 - 遵守Java集合契约:
Index类的equals和hashCode基于id保证键唯一性,TreeMap使用独立的Comparator避免契约冲突。 - 性能优化:核心操作(
containsKey、get、put)的时间复杂度为O(log n)(TreeMap排序)+ O(1)(HashMap查找),兼顾排序和查询效率。
内容的提问来源于stack exchange,提问作者Nolias
相关产品推荐
相关产品推荐

