【问题标题】:EnumMap or HashMap if lookup key is a String如果查找键是字符串,则 EnumMap 或 HashMap
【发布时间】:2012-05-13 18:55:05
【问题描述】:

我试图权衡使用EnumMapHashMap 的优缺点。因为,我将始终使用String 进行查找,看来带有String 键的HashMap 将是正确的选择。但是,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

【问题讨论】:

    标签: java collections hashmap enum-map


    【解决方案1】:

    首先,所有的键都是最终不可变的。你绝对应该使用EnumMap

    这就像 Ruby 中的哈希:

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

    :font_size 是 Ruby 中的符号,Java 中的最终静态对应物。

    【讨论】:

      【解决方案2】:

      如果可以枚举所有有效键,我会使用它,因为它可以确保您始终使用有效值。

      它还可以避免混淆,因为 String 可以用于很多事情,并且很容易将“Animal”字符串转换为用于其他用途的字符串。由于枚举类型通常不能与其他类型互换(除非您使用通用接口),因此编码出错的可能性较小。

      【讨论】:

      • 鉴于 Animal 枚举和 map 将只被 AnimalFactory 用于创建动物而没有其他地方,你仍然认为 EnumMap 更好吗?您如何看待使用 EnumMap 时在查找之前将字符串转换为枚举的成本?
      • 它与在 Map 本身中查找字符串的成本大致相同。 EnumMap 中没有加倍,因为它实际上是一个数组的包装器。 ;)
      【解决方案3】:

      Map 的键应该是不可修改且唯一的,这可以使用 Enum 来保证。

      与管理 String 相比,管理它会更容易,更不容易出错。

      所以选择 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】:

      如果可能的键集是有限的并且事先已知(如您的示例/问题所示),则枚举是对此的完美表示。正如其他人所说,使用枚举可以确保在使用密钥时不会出错。

      此外,这种 Map 的实现非常优化,因为键的范围是预先知道的(据我所知,EnumMap 在内部使用长度为 numberOfEnums 的数组,由枚举的序数)。

      所以我也推荐EnumMap

      有两件(小)事情要记住:

      • 您将无法通过继承添加特殊案例(例如,您无法扩展枚举,因此没有带有专门的哺乳动物地图的动物地图)
      • 将成员添加到枚举时,如果将其添加到其他成员的“中间”,则会更改序数。由于 EnumMap 可以使用此信息,因此如果您重新加载从旧版本枚举构造的 EnumMap(例如使用序列化),这可能会出现问题

      【讨论】:

      • 如你所说,EnumMap 更快,但在执行查找之前将输入字符串转换为枚举会产生额外的成本。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 2012-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多