Mengapa EnumMap bukan SortedMap di Java?

9

EnumMap<K extends Enum<K>, V> di Jawa jelas dipesan berdasarkan definisi enum yang terkait, seperti yang juga dapat Anda lihat di javadoc:

Peta Enum dipertahankan dalam urutan kuncinya (urutan penetapan konstanta enum). Hal ini tercermin dalam iterator dikembalikan oleh pandangan koleksi ( keySet(), entrySet(), dan values()).

Yang saya butuhkan adalah SortedMapmenggunakan enum sebagai tipe kunci. Saya ingin menggunakan metode seperti headMap()atau firstKey(), tapi saya ingin mendapat untung dari penambahan kinerja cpu + memori EnumMaps. Sebuah TreeMapsuara seperti terlalu banyak overhead di sini.

Pertanyaan : apakah ini baru saja terlewatkan dalam implementasi, apakah kemalasan (berasal dari AbstractMap) atau ada alasan bagus mengapa EnumMaptidak SortedMap?

kode mentah
sumber
Bagaimana dengan TreeSet?
Mohammed Deifallah
@MohammedDeifallah Itu sama sekali berbeda, tidak memiliki kunci ... Maksud Anda TreeMap?
deHaar
3
Saya dapat menemukan masalah ini untuk openjdk. Itu dari tahun 2005 namun masih terbuka / belum terselesaikan. Saya berasumsi tidak ada "alasan bagus" untuk ini tidak diterapkan.
Amongalen
1
Terima kasih atas jawaban yang sangat cepat, saya telah menambahkan bahwa saya menemukan TreeMap terlalu banyak overhead di sini, ditambah O (log n) untuk pertanyaan. Tapi pertanyaan saya tentu saja juga diperhitungkan untuk EnumSet dan SortedSet, masalah yang sama.
rawcode
@Amongalen: jawaban Anda memenuhi syarat sebagai jawaban untuk pertanyaan saya, meskipun itu tidak menjawab akar penyebabnya, selain "Oracle tidak fogging care". Bahkan google tidak menemukan masalah OpenJDK yang Anda sebutkan, jadi setidaknya itu akan membantu orang lain dengan masalah yang sama.
rawcode

Jawaban:

3

Ini tidak akan membuat jawaban untuk pertanyaan utama Anda (karena hanya desainer asli yang memiliki jawaban), tetapi satu pendekatan yang saya pertimbangkan adalah untuk Anda menerapkannya sendiri. Ketika mencoba untuk membuat SortedMapimplementasi berdasarkan EnumMap, saya datang dengan kelas berikut.

Ini jelas merupakan implementasi yang cepat dan kotor (dan perhatikan bahwa itu tidak sepenuhnya sesuai dengan SortedMap- karena persyaratan tampilan tidak terpenuhi), tetapi jika Anda membutuhkannya , Anda dapat memperbaikinya:

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

Dan untuk pengujian cepat (bug belum ditemukan):

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

Saya mendapat:

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
sumber
1
Anda berkomentar bahwa "peta yang dikembalikan BUKAN" tampilan "atau yang saat ini", tetapi metode ini (kepala / sub / ekor-Peta) HARUS mengembalikan tampilan.
assylias
1
Saya melihat bahwa tidak satu pun dari jawaban Anda yang benar - benar merupakan jawaban untuk pertanyaan utama saya, tetapi jawaban Anda setidaknya akan sangat membantu orang lain dengan masalah ini, jadi saya akan memberi Anda penghargaan atas upaya Anda. Mungkin seseorang di Oracle akan membaca dan menariknya ...
rawcode
@assylias Itu benar, dan saya menyebutkannya secara eksplisit di pos
ernest_k
Peta yang diurutkan yang mengimplementasikan semua operasi itu, dimaksudkan untuk mengeksploitasi sifat yang diurutkan, melalui pencarian linier ...
Holger
3

Buka permintaan fitur

Saya dapat menemukan masalah ini untuk OpenJDK . Itu dari tahun 2005 namun masih terbuka / belum terselesaikan.

Saya berasumsi tidak ada "alasan bagus" untuk ini tidak diterapkan.

Amongalen
sumber
terima kasih sudah melakukan ini. Sementara itu saya telah melihat jawaban ernest_k yang sebenarnya juga tidak menjawab pertanyaan saya, tetapi memunculkan solusi yang bagus untuk masalah yang mendasari pertanyaan saya. Maaf saya tidak memberi Anda kredit seperti yang saya sebutkan pertama, tapi saya pikir ernest_k layak mendapatkannya untuk pekerjaan ini.
rawcode
@ kode sandi Itu benar-benar dapat dimengerti. Jika saya jadi Anda, saya akan menerima jawaban ernest_k juga - itu jauh lebih bermanfaat daripada saya.
Amongalen