3

I have a class that looks something like this:

public class MessageBuilder{

  private enum MsgCodes{

    CODE_1("some string"),
    CODE_2("another string"),
    CODE_3("you get the idea");

    private String msg;

    MsgCodes(String msg){
      this.msg = msg;
    }

    private String text(){
      return msg;
    }
  }

  private MessageBuilder(){
    //prevents initialization outside the class
  }

  //Gives synchronized behaviour to initialization without enforcing it into getInstance()
  private static class Loader{
    static MessageBuilder INSTANCE = new MessageBuilder();
  }

  public static MessageBuilder getInstance(){
    return Loader.INSTANCE;
  }

  public String buildMessage(String[] codes){
    String res = "";
    for(String code : codes){
      res += QAmsg.valueOf(code).text();
    }
    return res;
  }

}

My concern is that overtime (meaning as the application develops) I will have more and more enum on this class (which I understand is not only a good but even the preferred way to keep constants used on only one class), I'm rather new to enum so I don't really know what will happen if this list becomes "too big" would this still be an efficient way to keep them?

Is there a different approach I could use so not the entire list but just the one code I'm using at the time gets instantiated? Would the enum instances only one time or is it instancing everything every time I use them?

I made the class a singleton thinking this would prevent me from having the enum list instantiated more than once, but this might be unnecessary as I don't fully understand enum behaviour.

Artemio Ramirez
  • 1,116
  • 1
  • 10
  • 23
  • 1
    Efficiency and memory has nothing to do with this. It might become a less optimal solution *designwise* later on with multiple hardcoded enums. – Kayaman Sep 12 '16 at 19:21
  • 1
    @Kayaman Do you seriously call that question an _exact duplicate_? I move to reopen. – Marko Topolnik Sep 12 '16 at 19:22
  • @MarkoTopolnik I concur; reopened. – Andy Turner Sep 12 '16 at 19:22
  • @Kayaman could you elaborate on why that is? I would also love to hear your opinion *designwise*, I'm trying my best not to make my question opinion based though – Artemio Ramirez Sep 12 '16 at 19:25
  • @MarkoTopolnik Well, not really. However it answered the "Would the enum instances only one time or is it instancing everything every time I use them?" question. – Kayaman Sep 12 '16 at 19:27
  • 2
    BTW As `MessageBuilder` can have only one instance you can make it an enum with one instance. This will simplify the code. – Peter Lawrey Sep 12 '16 at 19:28
  • @ArtemioRamirez I meant that at some point you may realize that it would have been easier to for example load the values from an external source. For example to introduce localization, or version dependent codes with several versions. – Kayaman Sep 12 '16 at 19:30
  • @Kayaman codes should never change, only the string they represent, also this is not to manage languages either, my application can output many different messages and some of those messages even come from other applications, so I'm adding this class to both centralize all those messages on a single place and to give me control over the messages that don't come from me (codes will never change but now I can change the actual string as I please). Is that what you mean? – Artemio Ramirez Sep 12 '16 at 19:47
  • @ArtemioRamirez I'm not talking about your situation. I'm talking about hypothetical situations where enums would become less optimal. As already established, there's no efficiency issue at least until you get to huge amounts of enums. – Kayaman Sep 12 '16 at 19:50
  • @Kayaman yes, I'm not talking about efficiency, just trying to understand your point on it being sub-optimal *designwise*, I guess I'm one of those rare cases who values opinions from others more experienced. It has been made clear this wouldn't turn into a performance issue and now I'm just trying to dig if there's something else to learn from this. – Artemio Ramirez Sep 12 '16 at 19:56
  • 2
    One way enums can turn bad is if you're going to change their definition often, especially if the changes you make are localized to _just_ the enum members. In that case you'll be forced to rebuild and redeploy the whole project on each change vs. just changing some config file on the fly. – Marko Topolnik Sep 12 '16 at 20:00
  • @PeterLawrey If I understand correctly, turning MessageBuilder into a single-element enum, would mean all of it's methods are also synchronized (I did notice that I had incorrectly made the buildMessage synchronized as there's no need for it to be). So for this scenario while the code would be simpler it would also have a negative effect preventing multiple threads to use the instance at the same time. – Artemio Ramirez Sep 12 '16 at 20:11
  • 1
    Being an `enum` doesn't make it's method synchronized or change them in any way, though you can do so if you need it. There is no real performance difference (there would be less indirection though) – Peter Lawrey Sep 12 '16 at 20:23

1 Answers1

8

Enum members are just public static final constants, therefore singletons. Let's suppose your list grows to 10,000 enum members and that each costs 1 KB. Even under these extravagant assumptions it will amount to 10 MB of Java heap.

So clearly, you should not worry about the memory consumption of enum members.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • 4
    From experience you can have about 4K enums before your static initialise block gets too large. ;) – Peter Lawrey Sep 12 '16 at 19:27
  • 1
    Due to the sill 64 K limit on bytecode instruction count, right? A compiler could get around it by splitting into several static init methods? – Marko Topolnik Sep 12 '16 at 19:29
  • 1
    `enum` use much the same memory as any other object. If you have thousands of enum values or thousands of object it won't make much difference. +1 – Peter Lawrey Sep 12 '16 at 19:30
  • 1
    You would think. ;) – Peter Lawrey Sep 12 '16 at 19:30
  • 2
    Yes, the compiler doesn't do it because it's a rare use case, but at least it _could_ do it and stay within specification? It could always split the method into submethods. – Marko Topolnik Sep 12 '16 at 19:31
  • 2
    It creates a limit for the size of an intialised array as well. If you have a large predifined array, you can't have as many enum values. If you add an argument to each constructor, you can't have as many :( – Peter Lawrey Sep 12 '16 at 19:34
  • 1
    @peter IMHO you've hit a design problem long before you hit such memory limitations: That many enum constants has the same order of magnitude as the complete vocabulary of natural languages. Also, I doubt IDEs could handle code completion drop downs for huge lists, and it would be well beyond the capacity of humans to comprehend. – Bohemian Sep 12 '16 at 20:47
  • 1
    @Bohemian agreed. I have only seen these limits reached in generated code or including data array which should have been in a file. – Peter Lawrey Sep 12 '16 at 21:05
  • 1
    @Marko Topolnik: only the class initializer is allowed to write to `static final` fields. Assume that you have a helper method, that instantiates/initializes all objects and returns them as array. Even then, you need `aload_0`, `sipush arrayIndex`, `aaload`, `putstatic fieldIndex`, for each constant, in other words 8 bytes per constant, limiting the number to ~8k constants. Btw. my quick test with current `javac` revealed a maximum of `2744` enum constants. It could be much more if the initializer didn’t prepare the array returned by `values()` (nonsensical premature optimization)… – Holger Sep 13 '16 at 09:55