ทำไม EnumMap ไม่ใช่ SortedMap ใน Java?


9

EnumMap<K extends Enum<K>, V> ใน Java ถูกจัดเรียงอย่างชัดเจนโดยนิยามของ enum ที่เกี่ยวข้องอย่างที่คุณเห็นใน javadoc:

แผนที่ Enum นั้นได้รับการบำรุงรักษาตามลำดับของกุญแจ (ตามลำดับที่ประกาศค่าคงที่ Enum) นี่คือภาพสะท้อนใน iterators กลับโดยมุมมองที่คอลเลกชัน ( keySet(), entrySet()และvalues())

สิ่งที่ฉันต้องการคือการSortedMapใช้ enum เป็นประเภทคีย์ ฉันต้องการใช้วิธีการเช่นheadMap()หรือfirstKey()แต่ฉันต้องการกำไรจากการเพิ่มประสิทธิภาพของซีพียู + หน่วยความจำของEnumMaps TreeMapเสียงเหมือนวิธีที่มากเกินไปค่าใช้จ่ายที่นี่

คำถาม : สิ่งนี้เพิ่งพลาดในการนำไปใช้หรือไม่มันเป็นความเกียจคร้าน (มาจากAbstractMap) หรือมีเหตุผลที่ดีว่าทำไมจึงEnumMapไม่ใช่SortedMap?


แล้ว TreeSet ล่ะ?
Mohammed Deifallah

@MohammedDeifallah นั่นแตกต่างกันโดยสิ้นเชิงมันไม่มีกุญแจ ... เจ้าหมายถึงTreeMapเหรอ?
deHaar

3
ฉันสามารถค้นหาปัญหานี้สำหรับ openjdk มันมาจากปี 2005 แต่ยังคงเปิด / ไม่ได้รับการแก้ไข ฉันคิดว่าไม่มี "เหตุผลที่ดี" สำหรับสิ่งนี้ที่ยังไม่ได้ใช้งาน
ระหว่าง

1
ขอบคุณสำหรับคำตอบที่รวดเร็วจริงๆฉันได้เพิ่มว่าฉันพบ TreeMap ค่าใช้จ่ายมากเกินไปที่นี่รวมทั้ง O (log n) สำหรับการค้นหา แต่แน่นอนว่าคำถามของฉันยังนับสำหรับ EnumSet และ SortedSet ปัญหาเดียวกัน
rawcode

@Amongalen: คำตอบของคุณมีคุณสมบัติเป็นคำตอบสำหรับคำถามของฉันแม้ว่ามันจะไม่ตอบสาเหตุที่แท้จริงนอกจาก "Oracle ไม่ได้ดูแลการพ่นหมอกควัน" แม้แต่ google ก็ไม่พบปัญหา OpenJDK ที่คุณพูดถึงดังนั้นอย่างน้อยก็จะช่วยผู้อื่นที่มีปัญหาเดียวกัน
rawcode

คำตอบ:


3

สิ่งนี้จะไม่ตอบคำถามหลักของคุณ (เพราะมีเพียงผู้ออกแบบดั้งเดิมเท่านั้นที่มีคำตอบ) แต่วิธีหนึ่งที่ฉันพิจารณาคือให้คุณใช้มันด้วยตัวเอง ในขณะที่พยายามทำการSortedMapใช้งานตามEnumMapฉันมากับคลาสต่อไปนี้

นี่เป็นการใช้งานที่รวดเร็วและสกปรก (และโปรดทราบว่ามันไม่สอดคล้องกับSortedMap- เนื่องจากไม่ได้ปฏิบัติตามข้อกำหนดการดู ) แต่ถ้าคุณต้องการคุณสามารถปรับปรุงได้:

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

และสำหรับการทดสอบอย่างรวดเร็ว (ยังไม่พบข้อบกพร่อง):

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

ฉันเข้าใจ:

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
คุณแสดงความคิดเห็นว่า "แผนที่ที่ส่งคืนไม่ใช่" มุมมอง "หรือมุมมองปัจจุบัน" แต่วิธีการเหล่านี้ (หัว / ย่อย / ท้ายแผนที่) ต้องแสดงมุมมอง
assylias

1
ฉันเห็นว่าคำตอบของคุณไม่ใช่คำตอบที่แท้จริงสำหรับคำถามหลักของฉัน แต่อย่างน้อยคำตอบของคุณจะเป็นประโยชน์อย่างมากกับคนอื่นที่มีปัญหานี้ดังนั้นฉันจะให้เครดิตสำหรับความพยายามของคุณ บางทีใครบางคนที่ Oracle จะอ่านและดึง ...
rawcode

@assylias ถูกต้องและฉันได้กล่าวถึงอย่างชัดเจนในโพสต์
ernest_k

แผนที่ที่เรียงลำดับที่ใช้การดำเนินการทั้งหมดที่ตั้งใจจะใช้ประโยชน์จากธรรมชาติที่ถูกจัดเรียงผ่านการค้นหาเชิงเส้น ...
Holger

3

เปิดคำขอคุณสมบัติ

ฉันสามารถค้นหาปัญหานี้สำหรับOpenJDKได้ มันมาจากปี 2005 แต่ยังคงเปิด / ไม่ได้รับการแก้ไข

ฉันคิดว่าไม่มี "เหตุผลที่ดี" สำหรับสิ่งนี้ที่ยังไม่ได้ใช้งาน


ขอบคุณที่ทำสิ่งนี้ ในระหว่างนี้ฉันได้เห็นคำตอบของ ernest_k ซึ่งไม่ได้ตอบคำถามของฉันจริง ๆ แต่นำเสนอทางออกที่ดีสำหรับปัญหาที่อยู่ภายใต้คำถามของฉัน ฉันขอโทษที่ฉันไม่ได้ให้เครดิตกับคุณตามที่กล่าวไว้ก่อนหน้านี้ แต่ฉันคิดว่า ernest_k สมควรได้รับมันสำหรับงานนี้
rawcode

@rawcode ที่เข้าใจได้โดยสิ้นเชิง ถ้าฉันเป็นคุณฉันจะยอมรับคำตอบของ ernest_k เช่นกัน - มันมีประโยชน์มากกว่าฉัน
ระหว่าง
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.