You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 05:44:58