Pourquoi EnumMap n'est-il pas un SortedMap en Java?

9

EnumMap<K extends Enum<K>, V> en Java est clairement ordonné par définition de l'énumération associée, comme vous pouvez également le voir dans le javadoc:

Les mappages d'énumération sont conservés dans l'ordre naturel de leurs clés (l'ordre dans lequel les constantes d'énumération sont déclarées). Cela se reflète dans les itérateurs renvoyés par les vues (collections keySet(), entrySet()et values()).

Ce dont j'ai besoin, c'est d' SortedMaputiliser une énumération comme type de clé. Je veux utiliser des méthodes comme headMap()ou firstKey(), mais je veux profiter des performances de mémoire cpu + ajoutées de EnumMaps. Un TreeMapson comme beaucoup trop de frais généraux ici.

Question : est-ce que cela a été manqué dans la mise en œuvre, était-ce la paresse (dérivée de AbstractMap) ou y a-t-il une bonne raison pour laquelle ce EnumMapn'est pas le cas SortedMap?

rawcode
la source
Et TreeSet?
Mohammed Deifallah
@MohammedDeifallah C'est totalement différent, il n'a pas de clés ... Vous vouliez dire TreeMap?
deHaar
3
J'ai pu trouver ce problème pour openjdk. Elle date de 2005, mais elle est toujours ouverte / non résolue. Je suppose qu'il n'y a aucune "bonne raison" pour que cela ne soit pas mis en œuvre.
Amongalen
1
Merci pour les réponses vraiment rapides, j'ai ajouté que je trouve TreeMap trop de surcharge ici, plus O (log n) pour les requêtes. Mais ma question compte bien sûr aussi pour EnumSet et SortedSet, même problème.
rawcode
@Amongalen: votre réponse est considérée comme une réponse à ma question, même si elle ne répond pas à la cause première, outre "Oracle ne s'embrouille pas". Même Google n'a pas trouvé le problème OpenJDK que vous avez mentionné, donc au moins cela aidera les autres avec le même problème.
rawcode

Réponses:

3

Cela ne répondra pas à votre question principale (car seuls les concepteurs originaux ont la réponse), mais une approche que j'envisageais était pour vous de l'implémenter vous-même. En essayant de faire une SortedMapimplémentation basée sur EnumMap, j'ai trouvé la classe suivante.

C'est sûrement une implémentation rapide et sale (et notez qu'elle n'est pas entièrement conforme SortedMap- car les exigences de vue ne sont pas remplies), mais si vous en avez besoin , vous pouvez l'améliorer:

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

Et pour un test rapide (bugs encore à trouver):

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

Je reçois:

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}
ernest_k
la source
1
Vous commentez que "la carte retournée n'est PAS une" vue "ou la vue actuelle", mais ces méthodes (head / sub / tail-Map) DOIVENT retourner des vues.
assylias
1
Je vois qu'aucune de vos réponses n'est vraiment une réponse à ma question principale, mais votre réponse sera au moins très utile à d'autres personnes ayant ce problème, donc je vous donnerai les crédits pour vos efforts. Peut-être que quelqu'un chez Oracle le lira et le
tirera
@assylias C'est vrai, et j'en ai fait mention explicite dans le post
ernest_k
Une carte triée qui implémente toutes ces opérations, destinée à exploiter la nature triée, via des recherches linéaires…
Holger
3

Ouvrir la demande de fonctionnalité

J'ai pu trouver ce problème pour OpenJDK . Elle date de 2005 mais n'est toujours pas résolue.

Je suppose qu'il n'y a aucune "bonne raison" pour que cela ne soit pas mis en œuvre.

Amongalen
la source
Merci d'avoir fait ça. Dans l'intervalle, j'ai vu la réponse d'ernest_k qui ne répond pas non plus à ma question, mais apporte une bonne solution au problème sous-jacent à ma question. Je suis désolé de ne pas vous avoir donné les crédits comme je l'ai mentionné en premier, mais je pense que ernest_k le mérite pour le travail.
rawcode
@rawcode C'est totalement compréhensible. Si j'étais vous, j'accepterais également la réponse d'ernest_k - elle est bien plus utile que la mienne.
Amongalen