Java 8 way to work with an enum

JavaEnumsJava 8

Java Problem Overview


I'm wondering what the best way is in Java 8 to work with all the values of an enum. Specifically when you need to get all the values and add it to somewhere, for example, supposing that we have the following enum:

public enum Letter {
 A, B, C, D;
}

I could of course do the following:

for (Letter l : Letter.values()) {
    foo(l);
}

But, I could also add the following method to the enum definition:

public static Stream<Letter> stream() {
    return Arrays.stream(Letter.values());
}

And then replace the for from above with:

Letter.stream().forEach(l -> foo(l));

Is this approach OK or does it have some fault in design or performance? Moreover, why don't enums have a stream() method?

Java Solutions


Solution 1 - Java

I'd go for EnumSet. Because forEach() is also defined on Iterable, you can avoid creating the stream altogether:

EnumSet.allOf(Letter.class).forEach(x -> foo(x));

Or with a method reference:

EnumSet.allOf(Letter.class).forEach(this::foo);

Still, the oldschool for-loop feels a bit simpler:

for (Letter x : Letter.values()) {
	foo(x);
}

Solution 2 - Java

Three questions: three-part answer:

Is it okay from a design point of view?

Absolutely. Nothing wrong with it. If you need to do lots of iterating over your enum, the stream API is the clean way to go and hiding the boiler plate behind a little method is fine. Although I’d consider OldCumudgeon’s version even better.

Is it okay from a performance point of view?

It most likely doesn’t matter. Most of the time, enums are not that big. Therefore, whatever overhead there is for one method or the other probably doesn’t matter in 99.9% of the cases.

Of course, there are the 0.1% where it does. In that case: measure properly, with your real-world data and consumers.

If I had to bet, I’d expect the for each loop to be faster, since it maps more directly to the memory model, but don’t guess when talking performance, and don’t tune before there is actual need for tuning. Write your code in a way that is correct first, easy to read second and only then worry about performance of code style.

Why aren’t Enums properly integrated into the Stream API?

If you compare Java’s Stream API to the equivalent in many other languages, it appears seriously limited. There are various pieces that are missing (reusable Streams and Optionals as Streams, for example). On the other hand, implementing the Stream API was certainly a huge change for the API. It was postponed multiple times for a reason. So I guess Oracle wanted to limit the changes to the most important use cases. Enums aren’t used that much anyway. Sure, every project has a couple of them, but they’re nothing compared to the number of Lists and other Collections. Even when you have an Enum, in many cases you won’t ever iterate over it. Lists and Sets, on the other hand, are probably iterated over almost every time. I assume that these were the reasons why the Enums didn’t get their own adapter to the Stream world. We’ll see whether more of this gets added in future versions. And until then you always can use Arrays.stream.

Solution 3 - Java

My guess is that enums are limited in size (i.e the size is not limited by language but limited by usage)and thus they don't need a native stream api. Streams are very good when you have to manipulate transform and recollect the elements in a stream; these are not common uses case for Enum (usually you iterate over enum values, but rarely you need to transform, map and collect them).

If you need only to do an action over each elements perhaps you should expose only a forEach method

	 public static void forEach(Consumer<Letter> action) {
		    Arrays.stream(Letter.values()).forEach(action);
	 }

     .... //example of usage
     Letter.forEach(e->System.out.println(e));

Solution 4 - Java

I think the shortest code to get a Stream of enum constants is Stream.of(Letter.values()). It's not as nice as Letter.values().stream() but that's an issue with arrays, not specifically enums.

> Moreover, why don't enums have a stream() method?

You are right that the nicest possible call would be Letter.stream(). Unfortunately a class cannot have two methods with the same signature, so it would not be possible to implicitly add a static method stream() to every enum (in the same way that every enum has an implicitly added static method values()) as this would break every existing enum that already has a static or instance method without parameters called stream().

> Is this approach OK?

I think so. The drawback is that stream is a static method, so there is no way to avoid code duplication; it would have to be added to every enum separately.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRumalView Question on Stackoverflow
Solution 1 - JavaNatixView Answer on Stackoverflow
Solution 2 - JavaJens SchauderView Answer on Stackoverflow
Solution 3 - JavaGiovanniView Answer on Stackoverflow
Solution 4 - JavaPaul BoddingtonView Answer on Stackoverflow