Perché EnumMap non è una SortedMap in Java?


9

EnumMap<K extends Enum<K>, V> in Java è chiaramente ordinato per definizione dell'enum associato, come puoi anche vedere nel javadoc:

Le mappe enum sono mantenute nell'ordine naturale delle loro chiavi (l'ordine in cui sono dichiarate le costanti enum). Ciò si riflette nelle iteratori restituiti dalle viste collezioni ( keySet(), entrySet(), e values()).

Ciò di cui ho bisogno è l' SortedMapuso di un enum come tipo di chiave. Voglio usare metodi come headMap()o firstKey(), ma voglio trarre profitto dalle prestazioni di memoria cpu + aggiunte di EnumMaps. A TreeMapsuoni come modo troppo in alto qui.

Domanda : mancava l'implementazione, era pigrizia (derivata da AbstractMap) o c'è una buona ragione per cui EnumMapnon lo è SortedMap?


Che dire di TreeSet?
Mohammed Deifallah,

@MohammedDeifallah È completamente diverso, non ha chiavi ... Intendevi TreeMap?
deHaar,

3
Sono stato in grado di trovare questo problema per openjdk. È del 2005 ma è ancora aperto / irrisolto. Suppongo che non ci siano "buone ragioni" per non essere implementato.
Tra il

1
Grazie per le risposte davvero rapide, ho aggiunto che trovo TreeMap troppo sovraccarico qui, oltre a O (log n) per le query. Ma la mia domanda ovviamente vale anche per EnumSet e SortedSet, stesso problema.
rawcode

@Amongalen: la tua risposta si qualifica come risposta alla mia domanda, anche se non risponde alla causa principale, oltre a "Oracle non appanna le cure". Nemmeno Google ha trovato il problema OpenJDK che hai citato, quindi almeno aiuterà gli altri con lo stesso problema.
rawcode

Risposte:


3

Questo non darà una risposta alla tua domanda principale (perché solo i progettisti originali hanno la risposta), ma un approccio che stavo prendendo in considerazione è stato quello di implementarlo da solo. Durante il tentativo di realizzare SortedMapun'implementazione basata su EnumMap, ho pensato alla seguente classe.

Questa è sicuramente un'implementazione rapida e sporca (e nota che non è completamente conforme SortedMap, perché i requisiti di visualizzazione non sono soddisfatti), ma se ne hai bisogno , puoi migliorarla:

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

E per un test rapido (bug ancora da trovare):

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

Ottengo:

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
Commenta che "la mappa restituita NON è una" vista "o quella corrente", ma questi metodi (head / sub / tail-Map) DEVONO restituire viste.
Assylias,

1
Vedo che nessuna delle tue risposte è davvero una risposta alla mia domanda principale, ma la tua risposta sarà almeno molto utile per altre persone con questo problema, quindi ti darò i crediti per i tuoi sforzi. Forse qualcuno di Oracle lo leggerà e lo tirerà ...
Rawcode

@assylias Esatto, e ne ho fatto esplicito riferimento nel post
ernest_k il

Una mappa ordinata che implementa tutte quelle operazioni, volte a sfruttare la natura ordinata, tramite ricerche lineari ...
Holger,

3

Apri richiesta funzionalità

Sono stato in grado di trovare questo problema per OpenJDK . È del 2005 ma è ancora aperto / irrisolto.

Suppongo che non ci sia alcun "buon motivo" per questo non essere implementato.


grazie per averlo fatto. Nel frattempo ho visto la risposta di ernest_k, che in realtà non risponde alla mia domanda, ma offre una buona soluzione al problema alla base della mia domanda. Mi dispiace di non averti dato i crediti come ho detto prima, ma penso che ernest_k se lo meriti per il lavoro.
rawcode

@rawcode Questo è totalmente comprensibile. Se fossi in te accetterei anche la risposta di ernest_k - è molto più utile della mia.
Tra il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.