Warum ist EnumMap in Java keine SortedMap?


9

EnumMap<K extends Enum<K>, V> in Java ist klar nach Definition der zugehörigen Aufzählung geordnet, wie Sie auch im Javadoc sehen können:

Enum-Maps werden in der natürlichen Reihenfolge ihrer Schlüssel verwaltet (der Reihenfolge, in der die Enum-Konstanten deklariert werden). Dies spiegelt sich in den Iteratoren von den Sammlungen Ansichten zurück ( keySet(), entrySet(), und values()).

Was ich brauche, ist die SortedMapVerwendung einer Aufzählung als Schlüsseltyp. Ich möchte Methoden wie headMap()oder verwenden firstKey(), aber ich möchte von der zusätzlichen CPU + Speicherleistung von EnumMaps profitieren . A TreeMapklingt hier viel zu viel Aufwand.

Frage : Wurde dies bei der Implementierung nur übersehen, war es Faulheit (abgeleitet von AbstractMap) oder gibt es einen guten Grund, warum dies EnumMapnicht der Fall ist SortedMap?


Was ist mit TreeSet?
Mohammed Deifallah

@MohammedDeifallah Das ist völlig anders, es hat keine Schlüssel ... Meinten Sie TreeMap?
deHaar

3
Ich konnte dieses Problem für openjdk finden. Es ist von 2005 noch offen / ungelöst. Ich würde annehmen, dass es keinen "guten Grund" dafür gibt, dass dies nicht implementiert wird.
Amongalen

1
Vielen Dank für die sehr schnellen Antworten. Ich habe hinzugefügt, dass ich TreeMap hier zu viel Aufwand finde, plus O (log n) für Abfragen. Aber meine Frage zählt natürlich auch für EnumSet und SortedSet, das gleiche Problem.
Rawcode

@Amongalen: Ihre Antwort gilt als Antwort auf meine Frage, obwohl sie nicht die Grundursache beantwortet, außer "Oracle beschlägt nicht". Nicht einmal Google hat das von Ihnen erwähnte OpenJDK-Problem gefunden, sodass es zumindest anderen bei demselben Problem hilft.
Rawcode

Antworten:


3

Dies gibt keine Antwort auf Ihre primäre Frage (da nur die ursprünglichen Designer die Antwort haben), aber ein Ansatz, den ich in Betracht gezogen habe, war, dass Sie sie selbst implementieren. Beim Versuch, eine SortedMapImplementierung basierend auf zu erstellen EnumMap, habe ich die folgende Klasse entwickelt.

Dies ist sicherlich eine schnelle und schmutzige Implementierung (und beachten Sie, dass sie nicht vollständig kompatibel ist SortedMap- da die Ansichtsanforderungen nicht erfüllt sind). Wenn Sie jedoch eine benötigen , können Sie sie verbessern:

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];
    }
}

Und für einen schnellen Test (Fehler müssen noch gefunden werden):

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));

Ich bekomme:

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
Sie kommentieren, dass "zurückgegebene Karte KEINE" Ansicht "oder die aktuelle" ist, aber diese Methoden (Kopf / Unter / Schwanz-Karte) MÜSSEN Ansichten zurückgeben.
Assylias

1
Ich sehe, dass keine Ihrer Antworten wirklich eine Antwort auf meine Hauptfrage ist, aber Ihre Antwort wird zumindest für andere Menschen mit diesem Problem sehr hilfreich sein, daher werde ich Ihnen die Credits für Ihre Bemühungen geben. Vielleicht liest und zieht jemand bei Oracle ...
Rawcode

@assylias Das ist richtig, und ich machte ausdrücklich erwähnt es in der Post
ernest_k

Eine sortierte Karte, die all diese Operationen implementiert, um die sortierte Natur über lineare Suchen auszunutzen…
Holger

3

Funktionsanforderung öffnen

Ich konnte dieses Problem für OpenJDK finden . Es ist von 2005 noch offen / ungelöst.

Ich würde annehmen, dass es keinen "guten Grund" dafür gibt, dass dies nicht implementiert wird.


Danke dafür. In der Zwischenzeit habe ich die Antwort von ernest_k gesehen, die meine Frage ebenfalls nicht beantwortet, aber eine gute Lösung für das meiner Frage zugrunde liegende Problem liefert. Es tut mir leid, dass ich Ihnen nicht die Credits gegeben habe, wie ich zuerst erwähnt habe, aber ich denke, ernest_k hat es für die Arbeit verdient.
Rawcode

@rawcode Das ist völlig verständlich. Wenn ich Sie wäre, würde ich auch die Antwort von ernest_k akzeptieren - sie ist viel hilfreicher als meine.
Amongalen
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.