1

I have a java class in which I store an Enum.(shown at the bottom of this question) In this enum, I have a method named toCommaSeperatedString() who returns a comma separated String of the enums values. I am using a StringBuilder after reading some information on performance in this question here.

Is the way I am converting this enum's values into a commaSeperatedString the most efficient way of doing so, and if so, what would be the most efficient way to remove the extra comma at the last char of the String?

For example, my method returns 123, 456, however I would prefer 123, 456. If I wanted to return PROPERTY1, PROPERTY2 I could easily use Apache Commons library StringUtils.join(), however, I need to get one level lower by calling the getValue method when I am iterating through the String array.

public class TypeEnum {
    public enum validTypes {
        PROPERTY1("123"),
        PROPERTY2("456");

        private String value;

        validTypes(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }

        public static boolean contains(String type) {
            for (validTypes msgType : validTypes.values()) {
                if (msgType.value.equals(type)) {
                    return true;
                }
            }
            return false;
        }

        public static String toCommaSeperatedString() {
            StringBuilder commaSeperatedValidMsgTypes = new StringBuilder();
            for(validTypes msgType : validTypes.values()) {
                commaSeperatedValidMsgTypes.append(msgType.getValue() + ", ");
            }
            return commaSeperatedValidMsgTypes.toString();
        }
    }
}
DevelopingDeveloper
  • 883
  • 1
  • 18
  • 41
  • 1
    You should have `.append(msgType.getValue()).append(", ")` instead of `.append(msgType.getValue() + ", ")`, but I think that's actually beside the point, because I agree with the answer saying you should just make the `String` once as e.g. a `private static final` field. – Radiodef Aug 10 '17 at 19:24
  • @Radiodef This is not my code, and for what is way longer of a story then needed I am not able to add the String field, but I do agree if I was able to modify that part of the Enum that a static String would be the easiest way to do this. – DevelopingDeveloper Aug 10 '17 at 19:40

5 Answers5

18

I wouldn't worry much about efficiency. It's simple enough to do this that it will be fast, provided you don't do it in a crazy way. If this is the most significant performance bottleneck in your code, I would be amazed.

I'd do it something like this:

return Arrays.stream(TypeEnum.values())
      .map(t -> t.value)
      .collect(Collectors.joining(','));

Cache it if you want; but that's probably not going to make a huge difference.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • This is something which I feel the best, doesn't matter efficiency – sForSujit Aug 10 '17 at 19:33
  • I completely understand this is of no way a bottleneck in my code, but I did want to make sure I wasn't writing way to much logic to find whether or not this piece of the array needed a comma or not. This answer is exactly what I was looking for. – DevelopingDeveloper Aug 10 '17 at 19:38
  • 3
    You could also create the Stream directly from the enum values: `Arrays.stream(TypeEnum.values()).map(t -> t.value).collect(Collectors.joining(','))` – rzueger Oct 15 '18 at 09:12
  • @rzueger yes, not sure why I didn't do that :) edited. – Andy Turner Oct 15 '18 at 11:08
2

The most efficient code is code that doesn't run. This answer can't ever change, so run that code as you have it once when creating the enums. Take the hit once, return the calculated answer every other time somebody asks for it. The savings in doing that would be far greater in the long term over worrying about how specifically to construct the string, so use whatever is clearest to you (write code for humans to read).

For example:

public enum ValidTypes {

    PROPERTY1("123"),
    PROPERTY2("345");

    private final static String asString = calculateString();
    private final String value;

    private static String calculateString() {
        return // Do your work here.
    }

    ValidTypes(final String value) {
        this.value = value;
    }

    public static String toCommaSeparatedString() {
        return asString;
    }
}
Todd
  • 30,472
  • 11
  • 81
  • 89
2

If you have to call this static method thousand and thousand of times on a short period, you may worry about performance and you should first check that this has a performance cost.
The JVM performs at runtime many optimizations.
So finally you could write more complex code without added value.


Anyway, the actual thing that you should do is storing the String returned by toCommaSeperatedString and returned the same instance.
Enum are constant values. So caching them is not a problem.

You could use a static initializer that values a static String field.
About the , character, just remove it after the loop.

public enum validTypes {

PROPERTY1("123"), PROPERTY2("456");

private static String valueSeparatedByComma;

static {
    StringBuilder commaSeperatedValidMsgTypes = new StringBuilder();
    for (validTypes msgType : validTypes.values()) {
        commaSeperatedValidMsgTypes.append(msgType.getValue());
        commaSeperatedValidMsgTypes.append(",");
    }

    commaSeperatedValidMsgTypes.deleteCharAt
    (commaSeperatedValidMsgTypes.length()-1);
    valueSeparatedByComma = commaSeperatedValidMsgTypes.toString();
}

public static String getvalueSeparatedByComma() {
    return valueSeparatedByComma;
}
davidxxx
  • 125,838
  • 23
  • 214
  • 215
2

A common pattern for the trailing comma problem I see is something like

String[] values = {"A", "B", "C"};
boolean is_first = true;
StringBuilder commaSeperatedValidMsgTypes = new StringBuilder();
for(String value : values){
    if(is_first){
        is_first = false;
    }
    else{
        commaSeperatedValidMsgTypes.append(',');
    }
    commaSeperatedValidMsgTypes.append(value);
}
System.out.println(commaSeperatedValidMsgTypes.toString());

which results in

A,B,C

Combining this with the answers about using a static block to initialize a static final field will probably give the best performance.

csunday95
  • 1,279
  • 10
  • 18
2

I usually add a static method on the enum class itself:

public enum Animal {
    CAT, DOG, LION;

    public static String possibleValues() {
        return Arrays.stream(Animal.values())
                .map(Enum::toString)
                .collect(Collectors.joining(","));
    }
}

So I can use it like String possibleValues = Animal.possibleValues();

Kent Munthe Caspersen
  • 5,918
  • 1
  • 35
  • 34