为什么EnumMap不是Java中的SortedMap?


9

EnumMap<K extends Enum<K>, V> Java中的Java显然是按相关枚举的定义排序的,正如您在Javadoc中也可以看到的那样:

枚举映射按其键的自然顺序(声明枚举常量的顺序)进行维护。这反映在集合视图返回的迭代器中(keySet()entrySet(),和values())。

我需要的是SortedMap使用枚举作为键类型。我想使用诸如headMap()或的方法firstKey(),但是我想从的cpu +内存性能中受益EnumMap s的。一个TreeMap听起来像是太多的开销在这里。

问题:这只是在实现中遗漏了吗?AbstractMap是懒惰(源自)还是有充分的理由为什么EnumMap不是SortedMap


那么TreeSet呢?
Mohammed Deifallah

@MohammedDeifallah这是完全不同的,它没有键...是TreeMap什么意思?
deHaar

3
我能够为openjdk 找到此问题。从2005年开始,但尚未解决。我认为没有任何“正当理由”未实现。
Amongalen

1
感谢您提供的快速答复,我补充道,我发现TreeMap在这里的开销太大,再加上O(log n)进行查询。但是我的问题当然也适用于EnumSet和SortedSet,这是同样的问题。
rawcode

@Amongalen:您的回答符合我的问题,即使它没有回答根本原因,除了“ Oracle不会模糊您的关心”。谷歌甚至没有找到您提到的OpenJDK问题,因此至少它可以帮助其他遇到相同问题的人。
rawcode

Answers:


3

这不会回答您的主要问题(因为只有原始设计者才有答案),但是我正在考虑的一种方法是让您自己实现它。在尝试制作一个SortedMap基于实现时EnumMap,我想到了以下课程。

这肯定是一种快速而肮脏的实现(并且请注意,它不完全符合SortedMap-因为未满足视图要求),但是如果需要,则可以对其进行改进:

class SortedEnumMap<K extends Enum<K>, V> 
    extends EnumMap<K, V> 
    implements SortedMap<K, V> {

    private Class<K> enumClass;
    private K[] values;

    public SortedEnumMap(Class<K> keyType) {
        super(keyType);
        this.values = keyType.getEnumConstants();
        this.enumClass = keyType;

        if (this.values.length == 0) {
            throw new IllegalArgumentException("Empty values");
        }
    }

    @Override
    public Comparator<? super K> comparator() {
        return Comparator.comparingInt(K::ordinal);
    }

    @Override
    public SortedMap<K, V> subMap(K fromKey, K toKey) {
        List<K> keys = Arrays.stream(this.values)
                .dropWhile(k -> k.ordinal() < fromKey.ordinal())
                .takeWhile(k -> k.ordinal() < toKey.ordinal())
                .collect(Collectors.toList());

        return this.forKeys(keys);
    }

    @Override
    public SortedMap<K, V> headMap(K toKey) {
        List<K> keys = new ArrayList<>();

        for (K k : this.values) {
            if (k.ordinal() < toKey.ordinal()) {
                keys.add(k);
            } else {
                break;
            }
        }

        return this.forKeys(keys);
    }

    @Override
    public SortedMap<K, V> tailMap(K fromKey) {
        List<K> keys = new ArrayList<>();

        for (K k : this.values) {
            if (k.ordinal() >= fromKey.ordinal()) {
                keys.add(k);
            }
        }

        return this.forKeys(keys);
    }

    //Returned map is NOT a "view" or the current one
    private SortedEnumMap<K, V> forKeys(List<K> keys) {
        SortedEnumMap<K, V> n = new SortedEnumMap<>(this.enumClass);
        keys.forEach(key -> n.put(key, super.get(key)));

        return n;
    }

    @Override
    public K firstKey() {
        return this.values[0];
    }

    @Override
    public K lastKey() {
        return this.values[this.values.length - 1];
    }
}

并进行快速测试(尚未发现错误):

SortedMap<Month, Integer> m = new SortedEnumMap(Month.class);

for (Month v : Month.values()) {
    m.put(v, v.getValue());
}

System.out.println("firstKey():       " + m.firstKey());
System.out.println("lastKey():        " + m.lastKey());
System.out.println("headMap/June:     " + m.headMap(Month.JUNE));
System.out.println("tailMap/June:     " + m.tailMap(Month.JUNE));
System.out.println("subMap/April-July " + m.subMap(Month.APRIL, Month.JULY));

我得到:

firstKey():       JANUARY
lastKey():        DECEMBER
headMap/June:     {JANUARY=1, FEBRUARY=2, MARCH=3, APRIL=4, MAY=5}
tailMap/June:     {JUNE=6, JULY=7, AUGUST=8, SEPTEMBER=9, OCTOBER=10, NOVEMBER=11, DECEMBER=12}
subMap/April-July {APRIL=4, MAY=5, JUNE=6}

1
您评论说“返回的地图不是“视图”或当前视图”,但是这些方法(head / sub / tail-Map)必须返回视图。
assylias

1
我发现您的答案都不能真正回答我的主要问题,但是您的答案至少会对其他有此问题的人有很大帮助,因此,我将为您的努力给予功劳。也许甲骨文公司的某人会阅读并提取它...
rawcode

@assylias没错,我在帖子中明确提及了此内容
ernest_k

一个排序后的地图,用于实现所有这些操作,旨在通过线性搜索来利用排序后的性质……
Holger

3

开启功能要求

我能找到这个问题OpenJDK的。从2005年开始,但尚未解决。

我认为没有任何“正当理由”未实现。


谢谢你这样做。同时,我看到了ernest_k的回答,该回答实际上也没有回答我的问题,但是为问题背后的问题提出了一个很好的解决方案。抱歉,我没有像我首先提到的那样给予您功劳,但是我认为ernest_k应该为工作而付出。
rawcode

@rawcode完全可以理解。如果我是您,我也将接受ernest_k的答案-它比我的要有用。
亚拉伦
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.