Почему EnumMap не является SortedMap в Java?


9

EnumMap<K extends Enum<K>, V> в Java четко упорядочено по определению связанного перечисления, как вы также можете увидеть в javadoc:

Карты перечислений поддерживаются в естественном порядке их ключей (порядок, в котором объявляются константы перечисления). Это находит свое отражение в итераторах возвращенного видом коллекций ( keySet(), entrySet()и values()).

Что мне нужно, так это SortedMapиспользование enum в качестве типа ключа. Я хочу использовать такие методы, как headMap()или firstKey(), но я хочу получить выгоду от дополнительной производительности процессора + памяти EnumMaps. А TreeMapзвучит как слишком много накладных расходов здесь.

Вопрос : было ли это просто пропущено при реализации, было ли это ленью (полученной из AbstractMap) или есть веская причина, почему EnumMapэто не так SortedMap?


Как насчет TreeSet?
Мохаммед Дейфалла

@MohammedDeifallah Это совершенно другое, у него нет ключей ... Вы имели в виду TreeMap?
deHaar

3
Я смог найти эту проблему для openjdk. Это с 2005, но все еще открыто / неразрешено. Я бы предположил, что нет «веских причин» для того, чтобы это не было реализовано.
Среди всех

1
Спасибо за очень быстрые ответы, я добавил, что нахожу TreeMap здесь слишком много служебной информации, плюс O (log n) для запросов. Но мой вопрос, конечно, также имеет значение для EnumSet и SortedSet, та же проблема.
rawcode

@Amongalen: ваш ответ квалифицируется как ответ на мой вопрос, хотя он и не отвечает основной причине, кроме того, что «Oracle не заботится о тумане». Даже Google не обнаружил упомянутую вами проблему OpenJDK, так что, по крайней мере, она поможет другим с этой же проблемой.
необработанный код

Ответы:


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
Вы комментируете, что «возвращенная карта НЕ является« представлением »или текущим», но эти методы (head / sub / tail-Map) ДОЛЖНЫ возвращать представления.
Ассилиас

1
Я вижу, что ни один из ваших ответов на самом деле не является ответом на мой основной вопрос, но ваш ответ будет, по крайней мере, очень полезным для других людей с этой проблемой, поэтому я дам вам кредиты за ваши усилия. Может быть, кто-то в Oracle прочтет и вытянет это ...
rawcode

@assylias Это верно, и я прямо упомянул об этом в посте
ernest_k

Сортированная карта, которая реализует все эти операции, предназначенные для использования отсортированной природы, с помощью линейного поиска ...
Хольгер

3

Запрос на открытую функцию

Я смог найти эту проблему для OpenJDK . Это с 2005, но все еще открыто / неразрешено.

Я бы предположил, что нет «веских причин» для того, чтобы это не было реализовано.


Спасибо за это. Тем временем я видел ответ ernest_k, который на самом деле также не отвечает на мой вопрос, но предлагает хорошее решение проблемы, лежащей в основе моего вопроса. Извините, я не дал вам кредитов, как я упоминал в первую очередь, но я думаю, что ernest_k заслуживает этого за работу.
rawcode

@rawcode Это совершенно понятно. На вашем месте я бы тоже принял ответ ernest_k - он намного полезнее моего.
Среди
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.