14

Some Message class is able to return a tag name based on tag number

Since this class is instanciated many times, I am a bit reluctant to create a HashMap for each instance:

public class Message {
  private HashMap<Integer,String> tagMap;

  public Message() {
    this.tagMap = new HashMap<Integer,String>();
    this.tagMap.put( 1, "tag1Name");
    this.tagMap.put( 2, "tag2Name");
    this.tagMap.put( 3, "tag3Name");
  }

  public String getTagName( int tagNumber) {
    return this.tagMap.get( tagNumber);
  }
}

In favor of hardcoding:

public class Message {
  public Message() {
  }

  public String getTagName( int tagNumber) {
    switch( tagNumber) {
      case 1: return "tag1Name";
      case 2: return "tag2Name";
      case 3: return "tag3Name";
      default return null;
    }
  }
}

When you put everything in the mix ( Memory, Performance, GC, ...)

Is there any reason to stick to HashMap?

MonoThreaded
  • 11,429
  • 12
  • 71
  • 102

5 Answers5

6

Initialize MAP in a static block.

And since you will be creating many objects of Message.you should write code like this

public class Message {

  private static HashMap tagMap;

  static {
     tagMap = new HashMap();
     tagMap.put( 1, "tag1Name");
     tagMap.put( 2, "tag2Name");
     tagMap.put( 3, "tag3Name");
  }

  public Message() {

  }

  public String getTagName( int tagNumber) {
    return tagMap.get( tagNumber);
  }
}
Byter
  • 1,132
  • 1
  • 7
  • 12
  • I didn't know about calling put() in static blocks. Sweet – MonoThreaded Aug 17 '12 at 09:58
  • Using a Map cannot be faster than using a switch, this makes no sense. – barjak Aug 17 '12 at 10:00
  • @Byter is there any proof that a Map (and also what implementation of Map) is faster then a switch? Did you actually test this? – Eugene Aug 17 '12 at 10:01
  • @Byter:A `HashMap` is `O(1)` (at best) but why is it faster construct than a `switch`?The `switch` is a branch instruction.It is not possible to be slower than a collection's function – Cratylus Aug 17 '12 at 10:02
  • sorry about that...Map enables us to write neat code.There is not much time difference between using a Map and a Switch. – Byter Aug 17 '12 at 10:05
  • @JamesB: Why is a static initialization block bad and what is the alternative here? – joergl Aug 17 '12 at 10:06
  • @Byter Really? Not much difference? :) From a branch prediction point of view a switch is REALLY bad and a TreeMap is way faster. – Eugene Aug 17 '12 at 10:07
  • @Eugene http://stackoverflow.com/questions/931890/what-is-more-efficient-a-switch-case-or-an-stdmap – Byter Aug 17 '12 at 10:08
  • @JamesB i still didnt get why using static block is such a Bad thing?? – Byter Aug 17 '12 at 10:09
  • @Byter your giving reference to a C++ question? :) Really? This conversation is useless. P.S. Read the second paragraph from the second answer by the way. ;) – Eugene Aug 17 '12 at 10:12
  • 1
    @joergl I prefer not to use them. There is usually always an alternative as demonstrated by the numerous responses here. Plus, you normally have to write extra code to handle them when unit testing. Just my opinion. – JamesB Aug 17 '12 at 10:15
  • 1
    You might even want to add `tagMap = Collections.unmodifiableMap(tagMap);` Only if the map won't change during runtime after the static block of course. – Pasukaru Jan 14 '16 at 14:15
1

Map can be used as command pattern in which key represents condition and value represents command to be executed the only drawback is object gets created before used so if you have large number of such conditions then you can opt for map else switch is always elegant approach if your conditions are few.

Amit Deshpande
  • 19,001
  • 4
  • 46
  • 72
0

Depends on what you need. For example if you ever needed to get all the tag names for display using a Map would pay off. Additionally if you replaced with a TreeMap you could get them sorted.
If you don't have such a need, then using a Map would be an overhead and your approach or an Enum would be much more efficient (you will have less readability though than you option of 5-10-20 case options)

Cratylus
  • 52,998
  • 69
  • 209
  • 339
0

Why not make the getTagName method static and lazy load it from a properties file?

public static String getTagName(int tagNumber) {
    if tagsByID == null) {
        // load tags from properties
    }
    return tagsByID.get(tagNumber);
}

Easy to test and configurable without a recompile.

JamesB
  • 7,774
  • 2
  • 22
  • 21
0

If all your tag values are consecutive in the interval [1..n] then you can use an array or maybe an ArrayList and have direct access to the values.

public class Message {
    private ArrayList<String> tags;

    public Message() {
        this.tags =  = new ArrayList<String>();
        this.tags.add("Unknown");
        this.tags.add("tag1Name");
        this.tags.add("tag2Name");
        this.tags.add("tag3Name");
    }

    public String getTagName(int tagNumber) {
        return this.tags.get(tagNumber);
    }
}

Alternative with an array.

public class Message {
    private static final String[] tags = {
        "N/A",
        "tag1Name",
        "tag2Name",
        "tag3Name",
        null,
        null,
        "tag6Name",
    };

    public Message() {
    }


    public String getTagName(int tagNumber) {
        if (tagNumber < 0 || tagNumber > tags.length) {
            throw new IllegalArgumentException();
        return tags[tagNumber];
    }
}
maba
  • 47,113
  • 10
  • 108
  • 118