canan
canan

Reputation: 63

using Map vs Enum


I need to keep a mapping which finds some properties given a String. For an example like below, I need to get possible colors for an animal given the description for that animal. I have "An animal with four legs" - not "CAT" - and need to find BROWN and GREY.
Keeping this in an enum makes code more maintainable and easy to read but it has additional cost of traversing all enum values each time I try to find colors. And also every time I need to get the colors list, a new array is going to be created.
My question is how much these additional costs affect the performance for Animal enum and String set(descriptions I've been given to map) sizes around 20 each? Also wonder if JVM optimizes these Arrays.asList calls.
Or any other design solutions you would recommend?
And would really appreciate if you can recommend a source to read more about those performance matters, what affects how much.
Thanks!

public enum AnimalsEnum{
    CAT("An animal with four legs"){
        @Override   
        public List<ColorsEnum> getPossibleColors(){
            return Arrays.asList(BROWN, GREY);
        }
    },
    BIRD("An animal with two legs and two wings"){
        @Override   
        public List<ColorsEnum> getPossibleColors(){
            return Arrays.asList(GREY, YELLOW, ORANGE);
        };
    };

    public List<ColorsEnum> getPossibleColors(){
        throw new AbstractMethodError();
    };
}


public enum ColorsEnum{
    ORANGE, BLUE, GREY, BROWN, YELLOW;
}

Upvotes: 1

Views: 3269

Answers (1)

Robert Kock
Robert Kock

Reputation: 6018

As far as your doubt "And also every time I need to get the colors list, a new array is going to be created" is concerned, you might try the following:

public enum AnimalsEnum
{
  CAT("An animal with four legs",
      EnumSet.of(ColorsEnum.BROWN, ColorsEnum.GREY)),
  BIRD("An animal with two legs and two wings",
       EnumSet.of(ColorsEnum.GREY, ColorsEnum.YELLOW, ColorsEnum.ORANGE));

  private AnimalsEnum(String              description,
                      EnumSet<ColorsEnum> possible_colors)
  {
    this.description = description;
    this.possible_colors = possible_colors;
  }

  public String getDescription()
  {
    return description;
  }

  public EnumSet<ColorsEnum> getPossibleColors()
  {
    return (possible_colors);
  }

  public static AnimalsEnum getAnimal(String description)
  {
    return (descr_map.get(description));
  }

  private String description;

  private EnumSet<ColorsEnum> possible_colors;

  private static HashMap<String, AnimalsEnum> descr_map;

  static
  {
    descr_map = new HashMap<String, AnimalsEnum>();
    for (AnimalsEnum animal : values())
    {
      descr_map.put(animal.getDescription(), animal);
    }    
  }

} // enum AnimalsEnum

EDIT:
Modified the answer adding a static method that returns the animal corresponding to its description.

EDIT2:
If you don't feel like keeping a separate Enum for your animals, you might try this:

public class AnimalColors extends HashMap<String, EnumSet<ColorsEnum>>
{
  private AnimalColors()
  {
    put("An animal with four legs", EnumSet.of(ColorsEnum.BROWN, ColorsEnum.GREY));
    put("An animal with two legs and two wings", EnumSet.of(ColorsEnum.GREY, ColorsEnum.YELLOW, ColorsEnum.ORANGE));
  }

  public static AnimalColors get()
  {
    return my_instance;
  }

  private static AnimalColors my_instance = new AnimalColors();

} // class AnimalColors

It's merely opinion based. It's up to you.

Upvotes: 4

Related Questions