28

I'm using enumerations to replace String constants in my java app (JRE 1.5).

Is there a performance hit when I treat the enum as a static array of names in a method that is called constantly (e.g. when rendering the UI)?

My code looks a bit like this:

public String getValue(int col) {
  return ColumnValues.values()[col].toString();
}

Clarifications:

  • I'm concerned with a hidden cost related to enumerating values() repeatedly (e.g. inside paint() methods).
  • I can now see that all my scenarios include some int => enum conversion - which is not Java's way.

What is the actual price of extracting the values() array? Is it even an issue?

Android developers

Read Simon Langhoff's answer below, which has pointed out earlier by Geeks On Hugs in the accepted answer's comments. Enum.values() must do a defensive copy

Nathaniel Ford
  • 20,545
  • 20
  • 91
  • 102
Asaf
  • 2,480
  • 4
  • 25
  • 33

7 Answers7

26

For enums, in order to maintain immutability, they clone the backing array every time you call the Values() method. This means that it will have a performance impact. How much depends on your specific scenario.

I have been monitoring my own Android app and found out that this simple call used 13.4% CPU time! in my specific case.

In order to avoid cloning the values array, I decided to simple cache the values as a private field and then loop through those values whenever needed:

private final static Protocol[] values = Protocol.values();

After this small optimisation my method call only hogged a negligible 0.0% CPU time

In my use case, this was a welcome optimisation, however, it is important to note that using this approach is a tradeoff of mutability of your enum. Who knows what people might put into your values array once you give them a reference to it!?

Simon Langhoff
  • 1,395
  • 3
  • 18
  • 28
  • How would enums not be immutable? You can't add to them at runtime. – skiwi Feb 04 '16 at 19:01
  • 5
    @skiwi in this case, when i ask for the possible values of this enum, I am given a reference to an array that contains said values. Because I have this reference, I can add elements to it, and the next time someone asks for the values of this enum, they will get a reference to the same array I just manipulated. Thus anyone who has asked for the values of this enum will see any previous changed made to the backing array. – Simon Langhoff Feb 04 '16 at 23:01
  • Right, I understand what you mean now – skiwi Feb 04 '16 at 23:06
  • This is ABSOLUTELY TRUE! I've been tracking down a vicious memory leak (3Gb in 20 sec (it's an audio synthesizer at 48kHz). I was iterating over enums using values() Copying to a static reference as above eliminated this problem. – Tim V Mar 03 '21 at 16:18
  • Wouldn't preventing adding to such array would make you gain the immutability of the enum back ? – Anddo Aug 17 '21 at 11:48
20

Enum.values() gives you a reference to an array, and iterating over an array of enums costs the same as iterating over an array of strings. Meanwhile, comparing enum values to other enum values can actually be faster that comparing strings to strings.

Meanwhile, if you're worried about the cost of invoking the values() method versus already having a reference to the array, don't worry. Method invocation in Java is (now) blazingly fast, and any time it actually matters to performance, the method invocation will be inlined by the compiler anyway.

So, seriously, don't worry about it. Concentrate on code readability instead, and use Enum so that the compiler will catch it if you ever try to use a constant value that your code wasn't expecting to handle.


If you're curious about why enum comparisons might be faster than string comparisons, here are the details:

It depends on whether the strings have been interned or not. For Enum objects, there is always only one instance of each enum value in the system, and so each call to Enum.equals() can be done very quickly, just as if you were using the == operator instead of the equals() method. In fact, with Enum objects, it's safe to use == instead of equals(), whereas that's not safe to do with strings.

For strings, if the strings have been interned, then the comparison is just as fast as with an Enum. However, if the strings have not been interned, then the String.equals() method actually needs to walk the list of characters in both strings until either one of the strings ends or it discovers a character that is different between the two strings.

But again, this likely doesn't matter, even in Swing rendering code that must execute quickly. :-)


@Ben Lings points out that Enum.values() must do a defensive copy, since arrays are mutable and it's possible you could replace a value in the array that is returned by Enum.values(). This means that you do have to consider the cost of that defensive copy. However, copying a single contiguous array is generally a fast operation, assuming that it is implemented "under the hood" using some kind of memory-copy call, rather than naively iterating over the elements in the array. So, I don't think that changes the final answer here.

Joe Carnahan
  • 2,373
  • 14
  • 15
  • thanks! exactly what i wanted to know. the bottom line is that everybody says not to worry about it - which is what i'm gonna do... – Asaf Mar 15 '10 at 13:34
  • 10
    `Enum.values()` can't give you a reference to a static array. What would happen if you changed a value in it? I has to copy it each time the method is called. – Ben Lings Mar 17 '10 at 22:29
  • 1
    Good point - You could mutate the array after you get it, and so a defensive copy is needed. It would make more sense for them to give you an *immutable* collection to iterate over, but they don't do what would make sense here, do they? ;-) I'll update my answer accordingly. – Joe Carnahan Mar 18 '10 at 00:16
  • 1
    If you do find that you're getting (for some reason) a performance impact, you can always keep a local cache of the enumeration value array. – deterb Jun 07 '10 at 02:20
  • 4
    "So, seriously, don't worry about it." What about on mobile devices when overhead needs to be minimized as much as possible. I'm wondering about just using a few byte constants rather than making an enum type? (for Android specifically) – Geeks On Hugs Aug 18 '12 at 14:41
2

As a rule of thumb : before thinking about optimizing, have you any clue that this code could slow down your application ?

Now, the facts.

enum are, for a large part, syntactic sugar scattered across the compilation process. As a consequence, the values method, defined for an enum class, returns a static collection (that's to say loaded at class initialization) with performances that can be considered as roughly equivalent to an array one.

Riduidel
  • 22,052
  • 14
  • 85
  • 185
  • yeh, i know: "premature optimization is the root of all evil". but this code is done in a Jtable renderer which gets rendered _a lot_. however, i was looking for someone who'd tell me that the compilers takes care of everything, and there're no gotchas here (like using reflection or something). – Asaf Mar 15 '10 at 11:42
  • Like Aaron says, it's by far better to store your enum entry in the table model than its index. This way, there is no lookup to do in the enum list. This is precisely the reason for the existence of TableModel, you know ... – Riduidel Mar 15 '10 at 12:48
2

If you're concerned about performance, then measure.

From the code, I wouldn't expect any surprises but 90% of all performance guesswork is wrong. If you want to be safe, consider to move the enums up into the calling code (i.e. public String getValue(ColumnValues value) {return value.toString();}).

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • If you use enums at the source, there is no performance loss since you won't have to do the conversion at all (or you'll at least save a method call). Also, you will get errors when you start using the enum in the wrong place. – Aaron Digulla Mar 15 '10 at 12:07
2

use this:

private enum ModelObject { NODE, SCENE, INSTANCE, URL_TO_FILE, URL_TO_MODEL,
    ANIMATION_INTERPOLATION, ANIMATION_EVENT, ANIMATION_CLIP, SAMPLER, IMAGE_EMPTY,
    BATCH, COMMAND, SHADER, PARAM, SKIN }
private static final ModelObject int2ModelObject[] = ModelObject.values();
Chameleon
  • 1,804
  • 2
  • 15
  • 21
1

If you're iterating through your enum values just to look for a specific value, you can statically map the enum values to integers. This pushes the performance impact on class load, and makes it easy/low impact to get specific enum values based on a mapped parameter.

public enum ExampleEnum {
    value1(1),
    value2(2),
    valueUndefined(Integer.MAX_VALUE);

    private final int enumValue;
    private static Map enumMap;
    ExampleEnum(int value){
       enumValue = value;
    }
    static {
       enumMap = new HashMap<Integer, ExampleEnum>();
       for (ExampleEnum exampleEnum: ExampleEnum.values()) {
           enumMap.put(exampleEnum.value, exampleEnum);
        }
    }
    public static ExampleEnum getExampleEnum(int value) {
        return enumMap.contains(value) ? enumMap.get(value) : valueUndefined;
    }
}
  • Thanks @jdoe7777777. I use a similar pattern a lot. It's not an answer to my question, but helpful nonetheless – Asaf Dec 27 '17 at 23:52
-1

I think yes. And it is more convenient to use Constants.

Artsiom Anisimau
  • 1,139
  • 3
  • 11
  • 26
  • 1
    Maybe more convenient during the development process but it's a maintenance nightmare. – Aaron Digulla Mar 15 '10 at 09:49
  • It depends. If code made by half-developer-half-plumper may be it is true. – Artsiom Anisimau Mar 15 '10 at 09:59
  • 5
    I'm with Aaron. Enums are nicer than constants IMO - they provide type safety, so that you get a compile-time error if you try to use a value from one area of the code where you're meant to use another - string constants don't prevent this sort of error. Then there are the other benefits of enums, such as them being able to express behaviour. – Jon Skeet Mar 15 '10 at 10:07
  • http://stackoverflow.com/questions/1858829/static-string-constants-vs-enum-in-java-5 + http://stackoverflow.com/questions/66066/what-is-the-best-way-to-implement-constants-in-java. i'm not inventing anything new... – Asaf Mar 15 '10 at 11:37