EnumMapがJavaのSortedMapではないのはなぜですか?


9

EnumMap<K extends Enum<K>, V> Javadocでも確認できるように、Javaでは関連する列挙型の定義によって明確に順序付けられています。

列挙型マップは、キーの自然な順序(列挙型定数が宣言されている順序)で維持されます。これは、コレクションビュー(によって返されるイテレータに反映されkeySet()entrySet()およびvalues())。

必要なのは、SortedMapキータイプとして列挙型を使用することです。headMap()またはのようなメソッドを使用したいがfirstKey()EnumMapsの追加されたcpu + memoryパフォーマンスから利益を得たい。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

回答:


3

これは最初の質問には答えません(元のデザイナーだけが答えを持っているため)が、私が検討していた1つのアプローチは、自分で実装することでした。に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)はビューを返さなければならない(MUST)。
アッシリア

1
私はあなたの答えのいずれもがあることがわかり、本当に私の主な質問への答えが、私はあなたの努力のためにあなたのクレジットを与えるので、あなたの答えは、この問題を持つ他の人に少なくとも非常に参考になります。たぶんOracleの誰かがそれを読んで引っ張るでしょう...
rawcode

@assyliasそうです、そして私は投稿でそれについて明示的に言及しました
ernest_k

線形検索を介して、ソートされた性質を利用することを目的とした、これらのすべての操作を実装するソートされたマップ…
Holger

3

機能のリクエストを開く

私は見つけることができた。この問題をするためにOpenJDKの。2005年からですが、まだオープン/未解決です。

これが実装されていない「正当な理由」はないと思います。


これをしてくれてありがとう 差し当たり、ernest_kの回答を見ましたが、これも実際には私の質問には回答しませんが、私の質問の根底にある問題に対する優れた解決策をもたらします。最初に述べたようにクレジットを提供しなかったのは残念ですが、ernest_kはこの作業に値すると思います。
rawcode

@rawcodeそれは完全に理解できます。私があなただったら、私はernest_kの答えも受け入れるでしょう-それは私のものよりもずっと役に立ちます。
Amongalen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.