Tại sao EnumMap không phải là SortedMap trong Java?


9

EnumMap<K extends Enum<K>, V> trong Java được sắp xếp rõ ràng theo định nghĩa của enum liên quan, như bạn cũng có thể thấy trong javadoc:

Bản đồ Enum được duy trì theo thứ tự tự nhiên của các khóa của chúng (thứ tự các hằng số enum được khai báo). Này được phản ánh trong các vòng lặp được trả về bởi các quan điểm bộ sưu tập ( keySet(), entrySet()values()).

Những gì tôi cần là SortedMapsử dụng enum làm loại khóa. Tôi muốn sử dụng các phương thức như headMap()hoặc firstKey(), nhưng tôi muốn kiếm lợi từ hiệu năng bộ nhớ cpu + của EnumMaps. Một TreeMapâm thanh như cách quá nhiều ở đây.

Câu hỏi : điều này chỉ bị bỏ qua khi thực hiện, đó có phải là sự lười biếng (xuất phát từ AbstractMap) hoặc có một lý do chính đáng tại sao EnumMapkhông phải là một SortedMap?


Những gì về Plantset?
Mohammed Deifallah

@MohammedDeifallah Điều đó hoàn toàn khác, nó không có chìa khóa ... Ý bạn là TreeMapsao?
deHaar

3
Tôi đã có thể tìm thấy vấn đề này cho openjdk. Đó là từ năm 2005 nhưng vẫn mở / chưa được giải quyết. Tôi cho rằng không có "lý do chính đáng" nào cho việc này không được thực hiện.
Amongalen

1
Cảm ơn vì câu trả lời thực sự nhanh chóng, tôi đã thêm rằng tôi thấy TreeMap quá nhiều chi phí ở đây, cộng với O (log n) cho các truy vấn. Nhưng tất nhiên câu hỏi của tôi cũng được tính cho Enumset và Sortedset, cùng một vấn đề.
rawcode

@Amongalen: câu trả lời của bạn đủ điều kiện là câu trả lời cho câu hỏi của tôi, mặc dù nó không trả lời nguyên nhân gốc rễ, bên cạnh "Oracle không quan tâm đến việc làm mờ". Thậm chí google không tìm thấy vấn đề OpenJDK mà bạn đã đề cập, vì vậy ít nhất nó sẽ giúp những người khác có cùng vấn đề.
rawcode

Câu trả lời:


3

Điều này sẽ không đưa ra câu trả lời cho câu hỏi chính của bạn (vì chỉ có các nhà thiết kế ban đầu mới có câu trả lời), nhưng một cách tiếp cận tôi đang xem xét là để bạn tự thực hiện nó. Trong khi cố gắng SortedMapthực hiện dựa trên EnumMap, tôi đã nghĩ ra lớp sau.

Đây chắc chắn là một triển khai nhanh và bẩn (và lưu ý rằng nó không hoàn toàn tuân thủ SortedMap- vì các yêu cầu xem không được đáp ứng), nhưng nếu bạn cần , bạn có thể cải thiện nó:

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

Và để kiểm tra nhanh (lỗi vẫn chưa được tìm thấy):

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

Tôi có:

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
Bạn nhận xét rằng "bản đồ được trả về KHÔNG phải là" chế độ xem "hoặc bản đồ hiện tại", nhưng các phương thức này (head / sub / tail-Map) PHẢI trả về lượt xem.
assylias

1
Tôi thấy rằng cả hai câu trả lời của bạn không thực sự là câu trả lời cho câu hỏi chính của tôi, nhưng câu trả lời của bạn ít nhất sẽ rất hữu ích cho những người khác với vấn đề này, vì vậy tôi sẽ cung cấp cho bạn các khoản tín dụng cho những nỗ lực của bạn. Có lẽ ai đó ở Oracle sẽ đọc và kéo nó ...
rawcode

@assylias Điều đó đúng, và tôi đã đề cập rõ ràng về nó trong bài đăng
ernest_k

Một bản đồ được sắp xếp thực hiện tất cả những hoạt động, nhằm khai thác bản chất được sắp xếp, thông qua tìm kiếm tuyến tính ...
Holger

3

Yêu cầu tính năng mở

Tôi đã có thể tìm thấy vấn đề này cho OpenJDK . Đó là từ năm 2005 nhưng vẫn mở / chưa được giải quyết.

Tôi cho rằng không có "lý do chính đáng" nào cho việc này không được thực hiện.


Cảm ơn bạn đã làm điều này. Trong khi đó, tôi đã thấy câu trả lời của ernest_k cũng không trả lời câu hỏi của tôi, nhưng đưa ra một giải pháp tốt cho vấn đề tiềm ẩn câu hỏi của tôi. Tôi xin lỗi tôi đã không cung cấp cho bạn các khoản tín dụng như tôi đã đề cập đầu tiên, nhưng tôi nghĩ ernest_k xứng đáng với công việc đó.
rawcode

@rawcode Điều đó hoàn toàn dễ hiểu. Nếu tôi là bạn, tôi cũng sẽ chấp nhận câu trả lời của ernest_k - nó hữu ích hơn tôi rất nhiều.
Amongalen
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.