Подтвердить что ты не робот

EnumMap или HashMap, если ключ поиска - это строка

Я пытаюсь взвесить плюсы и минусы использования EnumMap над HashMap. Так как я всегда буду искать с помощью String, кажется, что правильный выбор будет HashMap с ключом String. Тем не менее, EnumMap выглядит лучше, потому что он передает мое намерение ограничить ключи конкретным перечислением. Мысли?

Вот пример, показывающий, как я буду использовать Map:

enum AnimalType { CAT, DOG }
interface Animal {}
class Cat implements Animal {}
class Dog implements Animal {}

public class AnimalFactory {

    private static final Map<AnimalType, Animal> enumMap 
            = new EnumMap<AnimalType, Animal>(AnimalType.class);
    // versus
    private static final Map<String, Animal> stringMap 
            = new HashMap<String, Animal>();

    static {
        enumMap.put(AnimalType.CAT, new Cat());
        enumMap.put(AnimalType.DOG, new Dog());
        stringMap.put("CAT", new Cat());
        stringMap.put("DOG", new Dog());
    }
    public static Animal create(String type) {
        Animal result = enumMap.get(AnimalType.valueOf(type));
        Animal result2 = stringMap.get(type);
        return result;
    }
}

Предположим, что AnimalType перечисление и карта будут ТОЛЬКО использоваться AnimalFactory для создания животных и больше нигде.

Какую Map следует использовать?

4b9b3361

Ответ 1

Если все допустимые ключи могут быть перечислены, я бы использовал это, поскольку он гарантирует, что вы всегда работаете с допустимым значением.

Он также может избежать путаницы, поскольку String может использоваться для множества вещей и легко превратить строку "Animal" в строку, используемую для чего-то еще. Поскольку типы перечислений не являются взаимозаменяемыми с другими типами вообще (если вы не используете общий интерфейс), вероятность кодирования в коде меньше.

Ответ 2

Если набор возможных ключей конечен и известен заранее (как подсказывает ваш пример/вопрос), то перечисление является идеальным представлением об этом. Как и другие, использование перечисления гарантирует, что при использовании ключа не будет допущена ошибка.

Кроме того, эта реализация Карты довольно оптимизирована, поскольку диапазон ключей известен заранее (насколько я знаю, EnumMap использует массив длины numberOfEnums внутри, индексируется по порядковому номеру перечисления).

Поэтому я бы также рекомендовал EnumMap.

Две (маленькие) вещи, которые нужно иметь в виду:

  • вы не сможете добавлять специализированные случаи по наследству (вы не можете расширять перечисление, поэтому никаких карт ЖИВОТНЫХ со специализированными картами MAMMALS на стороне, например)
  • при добавлении члена к вашему перечислению, если вы добавите его "посередине" других членов, вы измените ординалы. Поскольку эта информация может использоваться EnumMap, это может оказаться проблематичным, если вы перезагрузите EnumMap, созданную из старой версии перечисления (например, используя сериализацию).

Ответ 3

Ключ карты должен быть немодифицируемым и уникальным, и это может быть гарантировано с помощью Enum.

Также управлять им было бы проще и меньше подверженности ошибкам по сравнению с управлением строкой.

Итак, зайдите в EnumMap.

Кроме того, поскольку у нас есть расширенные перечисления, мы можем прикрепить много других сведений и операций с помощью самих ключей.

enum AnimalType {

  Dog("I am dog and I hate cats", true), 
  CAT("I am cat and I love to eat rats", true),
  RAT("I am a mouse and I love tearing human cloths apart", false) ;

  private final String description;
  private final boolean isHelpFullToHuman;

  private AnimalType(String description , boolean isHelpFullToHuman) {
     this.description = description;
     this.isHelpFullToHuman = isHelpFullToHuman;
  }

  public boolean isHelpFullToHuman() {
     return isHelpFullToHuman;
  }

  public String getDescription() {
     return description;
  }

}

Ответ 4

Прежде всего, все ваши ключи окончательно неизменяемы. Вы должны обязательно использовать EnumMap.

Это похоже на Hash в Ruby:

options = { :font_size => 10, :font_family => "Arial" }

:font_size является символом в Ruby, конечной статической копии в Java.