Neden Java'da EnumMap bir SortedMap değil?


9

EnumMap<K extends Enum<K>, V> Java'da, javadoc'ta da görebileceğiniz gibi, ilişkili numaralandırmanın tanımı ile açıkça sıralanmıştır:

Enum haritaları anahtarlarının doğal sırasına göre (enum sabitlerinin bildirildiği sıra) tutulur. Bu koleksiyonları izleme geri yineleyicileri yansıtılır ( keySet(), entrySet()ve values()).

İhtiyacım olan SortedMapanahtar türü olarak bir numaralandırma kullanmak. headMap()Veya gibi yöntemler kullanmak istiyorum firstKey(), ama EnumMaps eklenen cpu + bellek performansından kar istiyorum . Bir TreeMapçok fazla havai burada yol gibi sesler.

Soru : Bu uygulamada kaçırılmış mıydı, tembellik miydi (türetilmiş AbstractMap) miydi EnumMapyoksa neden olmamasının iyi bir nedeni var SortedMapmı?


TreeSet ne olacak?
Muhammed Deifallah

@MohammedDeifallah Bu tamamen farklı, anahtarları yok ... Bunu mu demek istediniz TreeMap?
deHaar

3
Ben bulabildim bu sorunu OpenJDK için. 2005'ten beri hala açık / çözülmemiş. Bunun uygulanmaması için "iyi bir neden" olmadığını varsayabilirim.
Withinalen

1
Gerçekten hızlı yanıtlar için teşekkürler, burada çok fazla ek yükü TreeMap bulduğum ve sorguları için O (log n) ekledim. Ama benim sorum elbette EnumSet ve SortedSet için de geçerli.
rawcode

@Amongalen: Cevabınız, "Oracle bakım gerektirmiyor" yanı sıra, temel nedeni cevaplamasa da sorumun cevabı olarak nitelendirilir. Google bile bahsettiğiniz OpenJDK sorununu bulamadı, bu yüzden en azından aynı sorunu olan diğerlerine yardımcı olacak.
rawcode

Yanıtlar:


3

Bu, birincil sorunuza bir cevap vermeyecektir (çünkü sadece orijinal tasarımcıların cevabı vardır), ancak düşündüğüm bir yaklaşım, onu kendiniz uygulamanızdı. SortedMapDayalı bir uygulama yapmaya çalışırken EnumMap, ben aşağıdaki sınıf ile geldi.

Bu kesinlikle hızlı ve kirli bir uygulamadır (ve tam olarak uyumlu olmadığını unutmayın SortedMap- çünkü görünüm gereksinimleri karşılanmadı), ancak bir taneye ihtiyacınız varsa, geliştirebilirsiniz:

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

Hızlı bir test için (henüz bulunmayan hatalar):

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

Alırım:

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
"Döndürülen haritanın" görünüm "veya geçerli olan" DEĞİLDİĞİNE yorum yaparsınız, ancak bu yöntemler (head / sub / tail-Map) görünümler döndürmelidir ZORUNLU.
assylias

1
Cevaplarınızın hiçbirinin asıl soruma bir cevap olmadığını görüyorum , ancak cevabınız bu sorunu yaşayan diğer insanlara en azından çok yardımcı olacak, bu yüzden çabalarınız için size kredi vereceğim. Belki Oracle'dan biri okuyacak ve çekecektir ...
rawcode

@assylias Bu doğru ve yazıdan açıkça bahsettim
ernest_k

Tüm bu işlemleri uygulayan, sıralı doğayı sömürmeyi amaçlayan, doğrusal aramalar yoluyla sıralanmış bir harita…
Holger

3

Özellik isteğini aç

OpenJDK için bu sorunu bulabildim . 2005'ten beri hala açık / çözülmemiş.

Bunun uygulanmaması için "iyi bir neden" olmadığını varsayabilirim.


bunu yaptığınız için teşekkür ederim. Bu arada ben de aslında soruma cevap vermeyen ernest_k'in cevabını gördüm, ancak sorumun altında yatan sorun için güzel bir çözüm getiriyor. Özür dilerim, daha önce bahsettiğim gibi sana kredi vermedim, ama sanırım ernest_k bunu iş için hak ediyor.
rawcode

@rawcode Bu tamamen anlaşılabilir. Ben olsaydım ben de ernest_k'in cevabını kabul ederdim - bu benimkinden çok daha yararlı.
Amongalen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.