4

Is there any inefficiency in calling the values() function of a specific enum class multiple times?

I have seen instances of existing code where the results of values() are cached for reuse. Is this useful?

public enum Blah {

    private static final Blah [] _myValues = values()

    ...

    public static Blah findBlahFromName(String name) {
        for (Blah blah : _myValues) {
            ...
        }
    }

}
3
  • For what it's worth, in this particular situation I tend to use a Guava ImmutableMap<String,Blah>, since it's safe to share, can be wrapped, and is a bit simpler to use IMO. Commented Oct 10, 2013 at 18:37
  • You can see exactly how these are retrieved here Commented Oct 10, 2013 at 18:39
  • Caching here is known as micro-optimization. Unless it really so happens that an enum has become a bottleneck in your application. Commented Oct 10, 2013 at 18:53

2 Answers 2

9

Yes, it is inefficient, but there's another way to do it that's not nearly as expensive:

EnumSet.allOf(MyEnum.class);

EnumSet has special wiring into the JDK to allow it to reuse the underlying array.

Sign up to request clarification or add additional context in comments.

Comments

8

It's a good idea to cache the result of values() inside the enum itself if you use it multiple times. That's because, every time you invoke values() method, it creates a new array. So, that is really not required, as you are always going to get the same array elements.

As noted in comments, sharing a cached array will not be thread safe, as other thread can modify the indices in the array, as it's mutable. An option is to wrap the elements in a List<YourEnum>, and share the list using Collections.unmodifiableList().

4 Comments

Though it's not okay to share a cached copy of values() with someone you don't trust, because arrays in Java are always mutable, and someone could twiddle with the copy of the values.
Or just use [Enum.valueOf](docs.oracle.com/javase/7/docs/api/java/lang/…, java.lang.String%29) if you know the name() of an enum. I reason the cost of creating a new array is for most code negligible.
@chrylis option of Collections.unmodifiableList(..) wrapper to solve that, though then for(:) loop will create iterator, unlike when used with array.
EnumSet.allOf(MyEnum.class) is probably a lot simpler than most of these alternatives, and uses only constant memory (which you're already paying for with an Iterator).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.