MatBanik
MatBanik

Reputation: 26860

What are enums and why are they useful?

Today I was browsing through some questions on this site and I found a mention of an enum being used in singleton pattern about purported thread-safety benefits to such solution.

I have never used enums and I have been programming in Java for more than a couple of years now. And apparently, they changed a lot. Now they even do full-blown support of OOP within themselves.

Now why and what should I use enum in day to day programming?

Upvotes: 609

Views: 418165

Answers (29)

davidalayachew
davidalayachew

Reputation: 1519

Basics about Enums

What are Enums?

An Enumerated Type, also known as an Enum, is a very special data type where every single one of the values in its domain has a name (and usually, an index too).

A normal data type has values, but doesn't bother naming or numbering each value. An enum data type, on the other hand, enumerates every single one of its values, hence the name.

Also, an enum data type has a fixed number of instances that will ever exist for it. Meaning, if I say my enum data type called Direction has the values NORTH, SOUTH, EAST, and WEST, then that means that those 4 values are the only possible values that that enum data type can ever have (until we edit the code and recompile).

Why are they useful?

At first glance, naming and indexing values doesn't seem too useful. However, there at least 3 special abilities that you get for doing so.

  • Value Safety - You can create a custom domain that only contains meaningful values.

    • Before we had enums, we would treat a number as our value-carrier. For an example, in the Direction example from above, we would say NORTH is 0, EAST is 1, and so on. So, if I had a function that needed to take in a direction, I would just give that function a number parameter and then treat the different number values as if they represented a direction. But what happens if you pass in an 87? There's only 4 values! That is what Value Safety protects us against -- if we just use a number to represent our value, we run the risk of accidentally using an invalid number, causing our code to break at runtime. We can't catch the error at compile-time because all our code knows is that we are giving it a number. It has no way of knowing which numbers are valid or invalid at compile-time. Value Safety means that we don't pass in a number anymore - we pass in an enum value, which, in my Direction example, can only be one of my 4 values. If I try to pass in something that is not one of my 4 values, I get a compiler error, and that's exactly what I want.
  • Type Safety - Since it is a data type, you can prevent it from accidentally being confused for another data type.

    • Going back to the number point from before, let's say I have another data type called Orientation, with the values UP, DOWN, LEFT, and RIGHT. Now, if Orientation had been represented with numbers, UP would be 0, DOWN would be 1, etc. And let's say I have a function that asks for a Direction. Let's also say that I make a mistake and pass in Orientation.UP, when I actually meant to pass in Direction.NORTH. Well, by pure coincidence, my bug will not cause me pain (yet) because both values evaluate to 0. So, by accident, I got exactly what I wanted. But what if I actually wanted to enter Direction.SOUTH, but accidentally entered Orientation.DOWN? Well now the bug will cause me pain because Orientation.DOWN is 1, but 1 corresponds to Direction.EAST! This is a good example of the type of tricky bugs we would run into when using numbers as our value carriers. But, if we use enums to represent both, our code will catch the bug at compile-time because you can't use give the function an Orientation when it asked for a Direction. That is what type safety is - it prevents us from accidentally using one data type when we meant another.

  • Bounded and Indexed Domain - Enums allow you to specify at compile time EXACTLY how many instances of that type will exist at runtime. And not a minimum or maximum, but the exact number. They will all be instantiated the first time that you use the enum, like calling a method or referencing one of its fields or enum values. Knowing the number of instances gives you some POWERFUL guarantees. However, most (non-JVM) languages don't really take full advantage of this part. They might have a method that returns the whole domain, or fetches objects by index (useful for Random Number Generators), but that's usually the extent of their reach.

    • I'll be exploring these guarantees in WAY MORE DEPTH later in this answer, but for the Java section. Like I said, most (non-JVM) programming languages don't take enough advantage of these guarantees. Java takes these guarantees further than any other non-JVM language on the market, so I will save those benefits for later.

Java Enums

How are "Java Enums" different than other Enums? They are Classes too!

Java Enums follow all the rules I described earlier. They have Type Safety, Value Safety, and they have a Bounded and Indexed Domain.

However, Java Enums have one simple attribute that puts them on the bleeding edge of capability compared to all other non-JVM languages -- Almost anything a final class can do, a Java Enum can do too.

  • Final Classes can have instance fields? So can Java Enums!

    • If I were to make a CardSuit enum, not only can I have values HEART, SPADE, CLUB, and DIAMOND -- I could also give each of those values a String instance field that could hold the Emoji symbol for their respective Suit, simplifying my UI!
enum CardSuit
{

    HEART("♥️"), //<--- Yes, Java Strings can hold emoji characters!
    SPADE("♠️"),
    DIAMOND("♦️"),
    CLUB("♣️"), //<--- Trailing commas are allowed in Java Enums.
    ;

    public final String symbol;

    CardSuit(final String symbol)
    {

        this.symbol = symbol;

    }

}

//Later on, I can call it like this.

final String symbol = CardSuit.SPADE.symbol;
  • Final Classes can have instance methods? So can Java Enums!

    • If I were to make a Operator enum, not only can I have values GREATER_THAN, LESS_THAN, and EQUAL_TO -- I could also give each of those values a permits(int actualValue, int significantValue) method that could perform the calculation! This is an EXTREMELY powerful tactic because you basically captured the Strategy Pattern in its purest and simplest form.

enum Operator
{

   GREATER_THAN,
   GREATER_THAN_OR_EQUAL_TO,
   LESS_THAN,
   LESS_THAN_OR_EQUAL_TO,
   EQUAL_TO,
   NOT_EQUAL_TO,
   ;
   
   public boolean permits(final int actualValue, final int significantValue)
   {
   
      return 
         switch (this)
         {
         
            case GREATER_THAN             -> actualValue >  significantValue;
            case GREATER_THAN_OR_EQUAL_TO -> actualValue >= significantValue;
            case LESS_THAN                -> actualValue <  significantValue;
            case LESS_THAN_OR_EQUAL_TO    -> actualValue <= significantValue;
            case EQUAL_TO                 -> actualValue == significantValue;
            case NOT_EQUAL_TO             -> actualValue != significantValue;
         
         }
         ;
   
   }
   
}
  • Final Classes can have static fields and methods? So can Java Enums!

    • If I were to make a Shop enum where each enum value has a String location, I could create a static method fetchByLocation(String location) to filter my results down to the ones that matter!
import java.util.*;

enum Shop
{
    
    ShopA("Town 1"),
    ShopB("Town 1"),
    ShopC("Town 4"),
    ShopD("Town 2"),
    ShopE("Town 5"),
    ShopF("Town 3"),
    ShopG("Town 6"),
    ShopH("Town 2"),
    ShopI("Town 6"),
    ;
    
    //This is how you do static fields!
    public static final String COUNTRY_NAME = "SomeName";
    //You can even have static initialization blocks! Not shown here.

    public final String location;
    
    Shop(final String location)
    {
        
        this.location = location;
        
    }
    
    public static List<Shop> fetchByLocation(final String location)
    {
        
        final List<Shop> shops = new ArrayList<>();
        
        for (final Shop eachShop : shops)
        {
            
            if (eachShop.location.equals(location))
            {
                
                shops.add(eachShop);
                
            }
            
        }
        
        return shops;
        
    }
    
}
  • Final Classes can implement Interfaces? So can Java Enums!

    • I know I already used this before, but I am just going to steal the code from this answer (https://stackoverflow.com/a/15076852/10118965), since it captures the intent so perfectly.

    • Also, since enums can have Interfaces, then they can also have abstract methods too! In this example, you could achieve this by just removing implements Comparator<String> from the top, and then in the body, adding public abstract int compare(String s1, String s2); as if it was an instance method, like I showed above.

    • Also, unlike Final Classes, enum values can be Anonymous Classes, should you want to create part of the implementation inline. In some instances, that can simplify things.

enum StringComparator implements Comparator<String> {
    NATURAL {
        @Override
        public int compare(String s1, String s2) {
            return s1.compareTo(s2);
        }
    },
    REVERSE {
        @Override
        public int compare(String s1, String s2) {
            return NATURAL.compare(s2, s1);
        }
    },
    LENGTH {
        @Override
        public int compare(String s1, String s2) {
            return new Integer(s1.length()).compareTo(s2.length());
        }
    };
}

Please note though, the only thing that Final Classes can do that Java Enums cannot do is to have a class level Type Parameter. Here is a post going into better detail about why they can't -- Generics in enum for complex type checking

Of course, you can still put generics on your enum methods all you please, they just can't refer to a class-level type parameter.

What else can Java Enums do?

There's so much more! Back in the Bounded and Indexed Domain section, I mentioned that Enums allow you to specify at compile time EXACTLY how many instances of that type will exist at runtime. I also said that knowing the number of instances at compile-time gives you some POWERFUL guarantees. Here are some of those benefits now.

  • Singletons (and Multi-tons)
    • Enums are not only the best way to create singletons in Java (so far), but the officially encouraged way. If you want only one instance of an object, you should be using an enum, and not handrolling a singleton yourself.
  • Helper Methods
    • Enums come pre-baked with some helpful methods. For example, consider the enum java.time.DayOfWeek -- it models the days of the week -- Monday, Tuesday, etc. Here are some of the helpful methods that are automatically included, just because it is an enum. Every other enum that you make will have these methods included by default too.
      • valueOf(String name) -- If someone sends you a String, and you want to turn that into your Enum, simply call the static method valueOf that automatically comes with your enum. The String must exactly match your enum value's name. But if it does, then it's simple, easy deserialization.
      • name() -- Alternatively, this method will take the enum value (Monday, Tuesday, etc) and turn it into a String that exactly matches the enum values name. The previous method demonstrated simple, easy deserialization. This method is for simple, easy serialization.
      • values() -- If you want an array of all values in order, then you can just call this method. In this case, it will return an array containing all the days of the week, starting from MONDAY. This is good for looping or fetching an enum value by index.
      • compareTo(E other) -- All enums are Comparable<E> by default. So, you can easily tell whether the enum value in your hand comes before or after another enum value.
      • ordinal() -- And in case you just want the positional index of the enum value (maybe you want to randomly choose from any of the enum values), you can just call this method to get the enum's positional index. This may not seem that useful, but it has shockingly powerful uses.
  • Enum Collections
    • Enums have EXTREMELY FAST and memory-optimized versions of java.util.Set and java.util.Map -- respectfully called java.util.EnumSet and java.util.EnumMap.
      • To give an example of just how fast is fast, I did some (completely rudimentary and informal) performance tests, and I found EnumMap to be over 3 times faster than java.util.HashMap. And roughly 15% faster than java.util.IdentityHashMap, which is the non-enum equivalent of EnumMap. If you have an enum and you need a set or a map whose keys are the enum, then you need a reason to NOT use the enum variants. You should be using them by default when working with enums. It's a free performance boost.
        • And if that wasn't good enough, both of these enum-variants are actually ORDERED, which means that comparing EnumMap to HashMap and IdentityHashMap is an unfair comparison (for EnumMap!) because EnumMap is actually providing way more functionality and abilities than the hash variants. A "fair" comparison would be comparing EnumMap to java.util.TreeMap, which is even SLOWER than HashMap and IdentityHashMap. I hope you see just how insanely powerful these enum variants are compared to the rest of the Collection library.
      • And don't forget, I said they are also memory-optimized too. So not only are you getting the best performance that the Collection library has to offer, you are also getting one of the lightest memory-costs in the library too.
      • The reason for all of this speed and lightweight memory is because we know EXACTLY HOW MANY INSTANCES THERE ARE at compile-time. Knowing this means that we have optimization strategies that physically aren't possible for any of the other collections.
        • These enum-variants are able to represent inclusion using a byte[] (or a bit vector, which is very similar). For example, in EnumSet, it uses the enum's ordinal() method to be able to represent indexes in an array, and then just puts a 0 or a 1 to indicate whether or not the matching enum value is present in the set (I told you that ordinal() method had shockingly powerful uses). It is this byte[] that makes them so unbelievably fast and lightweight, because a byte[] is unbelievably fast and lightweight.

How well do Java Enums get along with other Java features?

Extremely well! Java as a language prioritizes cohesiveness. That means that a feature that is added to the language should play nicely with all other features. Enums are no exception to this. So as a result, anywhere that you can use a Final Class, you can use an Enum there too!

However, there are some special interactions between Enums and other features of Java. Those interactions are what I will highlight in this section.

I should also mention, this is the part of the post that is more 2023 focused. As new features have been added, there have been more features for Java Enums to have special interactions with.

As a very quick note, I will reemphasize what I said before - pretty much the only feature that Java Enums don't get along perfectly with is generics, and even then, it's only class-level generics. Anything not class-level works beautifully.

  • Enums + Switch = Single-Type Exhaustiveness Checking

    • Since we know the exact number of values that an enum data type can have at compile time, that gives the compiler a special ability when using a switch expression/statement.
      • If the value we are switching over is an enum, then a switch expression/statement will give you the option to opt into Exhaustiveness Checking (Ctrl+F "Exhaustiveness of switch Expressions")
        • Exhaustiveness checking is a special ability that says, if all of the case labels in our switch expression/statement cover the full domain of possible values for what we are switching over (with the exception of null), then our switch is considered exhaustive. This is EXTREMELY POWERFUL. Let's say that I use my Direction enum again. But let's say that I add the diagonal values to it -- NORTHEAST, SOUTHEAST, etc. If I have a switch expression that switches on an enum value, then that means that that code won't compile unless I cover every single case. So, back when my Direction enum only had 4 values, that meant I only needed 4 case labels. As long as I have those 4 case labels, my enum compiles. But once I add the 4 diagonals as well, bringing my total up to 8, that switch expression will no longer compile because it is no longer exhaustive. This is HUGE because it completely eliminates those I-changed-it-here-but-forgot-to-change-it-there type of bugs that everyone runs into all the time.
      • Of course, if you do not want Exhaustiveness Checking, you can easily opt out of it by just using a default clause. Simply mention what the default behaviour should be if you don't match any of the other case labels, and then you will be good to go. That said, it is strongly encouraged to NOT opt out. Simply update the enum to mention what it should do in those instances by adding do nothing (or, do the same thing) case labels. Of course, if that is not an option for you, or it is simply too inconvenient (library maintainers), then by all means, that is what the default clause is for.
  • Enums + Switch Patterns + Sealed Types = Multi-Type Exhaustiveness Checking

    • Sometimes, we have an enum that we would like to break up into multiple parts, but we still want to get Exhaustiveness Checking. In situations such as those, the solution is to include Sealed Types and Switch Patterns to the mix.
      • A Sealed Type is a type where only a fixed number of types can extend it, and those types are known at compile-time.
      • A Switch Pattern is a switch statement/expression where the case labels don't hold constants, they hold type patterns. A type pattern is where we test a value to see if it is assignable to a type. If so, we create a new variable of the focused type, and assign the value to that variable. Read more in the link above for Switch Patterns.
        • To demonstrate all 3 of these combined, let's say I have an enum Alphabet. It has 26 values -- the 26 letters of the English Language. But what if I want to distinguish between vowels and consonants? Well, all I need to do is to turn my Alphabet enum into a Sealed Interface that only permits 2 other enums -- Consonant and Vowel. From there, I provide Vowel with the 5 vowels, and then put the rest of the Alphabet values into Consonant. Once I have that, I can switch over an instance of Alphabet, and still get exhaustiveness checking, while being able to "chunk" my Exhaustiveness Checks by type. If I want to handle all instances of Consonant in the same way while handling instances of Vowel individually, I can simply pass in the type Consonant as one of my type patterns for a single case label, and then the other case labels will be for each value of Vowel. This will still give me Exhaustiveness Checking, but allowing me to focus it on the parts that matter.
  • More (potentially, not certainly) coming in the future!

    • In the future, it is extremely likely that we will get Constant Patterns. That means that, anywhere that we do pattern-matching, we will be able to pass in our enum value as a Constant Pattern. In that situation, enums will become exponentially more valuable, as that will give us yet another form of Exhaustiveness Checking that currently isn't possible.

The Tradeoffs when using Java Enums

Sacrifices

As you can see, Java Enums are powerful and flexible. There are so many use cases, and they extend into a lot of different domains. They have abilities that are unique (not just within Java, but amongst all non-JVM languages).

That said, everything that is good about enums comes because we make sacrifices along the way. We don't just get this stuff for free - there is a cost. There always is a cost.

The Costs of using Java Enums

As mentioned, Java Enums charge a tax for their use, much like every feature in the Java language.

  • If you want to add/remove/update a value in your Java Enum, you may have to recompile code that does Exhaustiveness Checking.

    • You could argue that this is a feature, not a bug. I certainly agree. But bug or not, it is a price you must pay. If you decide that you want your Direction enum to have diagonals, then you must recompile your switch expressions that don't have defaults or catch-all's. At that point, it becomes a question of whether or not it is worth it for you to not have the default clause.
  • Enums are Final Classes, not just Classes

    • Since enums are FINAL Classes, that means that they cannot be extended. This limits their applicability in a few ways, but for good reason. After all, if your enum can be arbitrarily extended, how would you go about implementing values() or ordinal()?

When should we use Java Enums?

Java Enums are best used when the following 3 things are true.

  1. You know all the values of a type at compile-time

    • This means that whatever domain you are trying to model is a domain where you, the person consuming this information, can think through every single possible value in the domain. A good example might be an enum for the months of a year. You can think up all 12 months, so that means that we know all the values of the Month type at compile-time.
  2. The number of values is "small enough"

    • One user on this thread mentioned that you don't want to put Days of the year into an enum because there are 2 many values (366). I respectfully disagree, but every person's boundary for what is too much is different.

      • That said, there is a limit to maximum number of enum values you can include. If I'm not mistaken, Java says that all class files can not have more than ~65k fields. So, if your enum has fields, there's your answer. And for me, I have found that I start hitting the limit once my enum gets over 2k values (my enum has multiple values). That said, if you find yourself reaching the thousands, chances are good that the work you are doing has simply gotten too big for an enum to handle. Time to reach in and find a better tool.
  3. You will never change the enum values -- OR, your enum values change infrequently enough that your end users are fine potentially recompiling when the change happens.

    • Consider the Planet enum. That is a good candidate for an enum. All of its values are known at runtime, and it's certainly small enough. And at first glance, this seems to be an unchanging enum. But as it turns out, this one actually did need to change in the past -- when we turned Pluto from a Planet to a Dwarf Planet. I don't know the context, but I would assume that most users are fine swapping their program when it becomes clear that Pluto was no longer a Planet. Again, judge how quickly your users are willing and able to recompile their code. Then compare that to how likely and frequently you plan to update and change the enum. If change is more frequent than what your users desire, there is your answer.
    • Also, users are a lot more likely to recompile if you remove or modify enum values. Adding enum values are less likely to require a code change. If you only plan to add enum values, you should feel more confident storing this data as an enum.w

Upvotes: 0

Mircea Sirghi
Mircea Sirghi

Reputation: 616

When a variable can take certain values, it is useful to use enums. It encapsulates all possible values from a specific group.

One advantage is that it will not accept other values and you have the ability to throw a Runtime exception without losing processing resources in vain.

You can also assign different behaviors per enum value which helps implementing the Strategy pattern.

In the end, it makes the code more readable as you don't pollute it with new operator.

Upvotes: 0

Oleg Poltoratskii
Oleg Poltoratskii

Reputation: 806

The enum based singleton

a modern look at an old problem

This approach implements the singleton by taking advantage of Java's guarantee that any enum value is instantiated only once in a Java program and enum provides implicit support for thread safety. Since Java enum values are globally accessible, so they can be used as a singleton.

public enum Singleton {
    SINGLETON; 
    public void method() { }
}

How does this work? Well, line two of the code may be considered to something like this:

public final static Singleton SINGLETON = new Singleton(); 

And we get good old early initialized singleton.

Remember that since this is an enum you can always access to the instance via Singleton. SINGLETON as well:

Singleton s = Singleton.SINGLETON;

Advantages

  • To prevent creating other instances of singleton during deserialization use enum based singleton because serialization of enum is taken care by JVM. Enum serialization and deserialization work differently than for normal java objects. The only thing that gets serialized is the name of the enum value. During the deserialization process, the enum valueOf method is used with the deserialized name to get the desired instance.
  • Enum based singleton allows to protect itself from reflection attacks. The enum type actually extends the java Enum class. The reason that reflection cannot be used to instantiate objects of enum type is that the java specification disallows and that rule is coded in the implementation of the newInstance method of the Constructor class, which is usually used for creating objects via reflection:
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
    throw new IllegalArgumentException("Cannot reflectively create enum objects");
  • Enum is not supposed to be cloned because there must be exactly one instance of each value.
  • The most laconic code among all singleton realizations.

Disadvantages

  • The enum based singleton does not allow lazy initialization.
  • If you changed your design and wanted to convert your singleton to multiton, enum would not allow this. The multiton pattern is used for the controlled creation of multiple instances, which it manages through the use of a map. Rather than having a single instance per application (e.g. the java.lang.Runtime) the multiton pattern instead ensures a single instance per key.
  • Enum appears only in Java 5 so you can not use it in the prior version.

There are several realizations of singleton pattern each one with advantages and disadvantages.

  • Eager loading singleton
  • Double-checked locking singleton
  • Initialization-on-demand holder idiom
  • The enum based singleton

A detailed description each of them is too verbose so I just put a link to a good article - All you want to know about Singleton

Upvotes: 1

Nicolas Voron
Nicolas Voron

Reputation: 2996

In addition to @BradB Answer :

That is so true... It's strange that it is the only answer who mention that. When beginners discover enums, they quickly take that as a magic-trick for valid identifier checking for the compiler. And when the code is intended to be use on distributed systems, they cry... some month later. Maintain backward compatibility with enums that contains non static list of values is a real concern, and pain. This is because when you add a value to an existing enum, its type change (despite the name does not).

"Ho, wait, it may look like the same type, right? After all, they’re enums with the same name – and aren’t enums just integers under the hood?" And for these reasons, your compiler will likely not flag the use of one definition of the type itself where it was expecting the other. But in fact, they are (in most important ways) different types. Most importantly, they have different data domains – values that are acceptable given the type. By adding a value, we’ve effectively changed the type of the enum and therefore break backward compatibility.

In conclusion : Use it when you want, but, please, check that the data domain used is a finite, already known, fixed set.

Upvotes: 1

user10309496
user10309496

Reputation:

Enums are like classes. Like class, it also has methods and attributes.

Differences with class are: 1. enum constants are public, static , final. 2. an enum can't be used to create an object and it can't extend other classes. But it can implement interfaces.

Upvotes: -1

Christophe Roussy
Christophe Roussy

Reputation: 16999

Use enums for TYPE SAFETY, this is a language feature so you will usually get:

  • Compiler support (immediately see type issues)
  • Tool support in IDEs (auto-completion in switch case, missing cases, force default, ...)
  • In some cases enum performance is also great (EnumSet, typesafe alternative to traditional int-based "bit flags.")

Enums can have methods, constructors, you can even use enums inside enums and combine enums with interfaces.

Think of enums as types to replace a well defined set of int constants (which Java 'inherited' from C/C++) and in some cases to replace bit flags.

The book Effective Java 2nd Edition has a whole chapter about them and goes into more details. Also see this Stack Overflow post.

Upvotes: 5

Vincent Tang
Vincent Tang

Reputation: 4160

Instead of making a bunch of const int declarations

You can group them all in 1 enum

So its all organized by the common group they belong to

Upvotes: 0

Costi Ciudatu
Costi Ciudatu

Reputation: 38195

Besides the already mentioned use-cases, I often find enums useful for implementing the strategy pattern, following some basic OOP guidelines:

  1. Having the code where the data is (that is, within the enum itself -- or often within the enum constants, which may override methods).
  2. Implementing an interface (or more) in order to not bind the client code to the enum (which should only provide a set of default implementations).

The simplest example would be a set of Comparator implementations:

enum StringComparator implements Comparator<String> {
    NATURAL {
        @Override
        public int compare(String s1, String s2) {
            return s1.compareTo(s2);
        }
    },
    REVERSE {
        @Override
        public int compare(String s1, String s2) {
            return NATURAL.compare(s2, s1);
        }
    },
    LENGTH {
        @Override
        public int compare(String s1, String s2) {
            return new Integer(s1.length()).compareTo(s2.length());
        }
    };
}

This "pattern" can be used in far more complex scenarios, making extensive use of all the goodies that come with the enum: iterating over the instances, relying on their implicit order, retrieving an instance by its name, static methods providing the right instance for specific contexts etc. And still you have this all hidden behind the interface so your code will work with custom implementations without modification in case you want something that's not available among the "default options".

I've seen this successfully applied for modeling the concept of time granularity (daily, weekly, etc.) where all the logic was encapsulated in an enum (choosing the right granularity for a given time range, specific behavior bound to each granularity as constant methods etc.). And still, the Granularity as seen by the service layer was simply an interface.

Upvotes: 49

tinker_fairy
tinker_fairy

Reputation: 1351

What is an enum

  • enum is a keyword defined for Enumeration a new data type. Typesafe enumerations should be used liberally. In particular, they are a robust alternative to the simple String or int constants used in much older APIs to represent sets of related items.

Why to use enum

  • enums are implicitly final subclasses of java.lang.Enum
  • if an enum is a member of a class, it's implicitly static
  • new can never be used with an enum, even within the enum type itself
  • name and valueOf simply use the text of the enum constants, while toString may be overridden to provide any content, if desired
  • for enum constants, equals and == amount to the same thing, and can be used interchangeably
  • enum constants are implicitly public static final

Note

  • enums cannot extend any class.
  • An enum cannot be a superclass.
  • the order of appearance of enum constants is called their "natural order", and defines the order used by other items as well: compareTo, iteration order of values, EnumSet, EnumSet.range.
  • An enumeration can have constructors, static and instance blocks, variables, and methods but cannot have abstract methods.

Upvotes: 9

James P.
James P.

Reputation: 19607

Now why and what for should I used enum in day to day programming?

You can use an Enum to represent a smallish fixed set of constants or an internal class mode while increasing readability. Also, Enums can enforce a certain rigidity when used in method parameters. They offer the interesting possibility of passing information to a constructor like in the Planets example on Oracle's site and, as you've discovered, also allow a simple way to create a singleton pattern.

ex: Locale.setDefault(Locale.US) reads better than Locale.setDefault(1) and enforces the use of the fixed set of values shown in an IDE when you add the . separator instead of all integers.

Upvotes: 21

Abhishek Bhandari
Abhishek Bhandari

Reputation: 623

Enum? Why should it be used? I think it's more understood when you will use it. I have the same experience.

Say you have a create, delete, edit and read database operation.

Now if you create an enum as an operation:

public enum operation {
    create("1")
    delete("2")
    edit("3")
    read("4")

    // You may have is methods here
    public boolean isCreate() {
        return this.equals(create);
    }
    // More methods like the above can be written

}

Now, you may declare something like:

private operation currentOperation;

// And assign the value for it 
currentOperation = operation.create

So you can use it in many ways. It's always good to have enum for specific things as the database operation in the above example can be controlled by checking the currentOperation. Perhaps one can say this can be accomplished with variables and integer values too. But I believe Enum is a safer and a programmer's way.

Another thing: I think every programmer loves boolean, don't we? Because it can store only two values, two specific values. So Enum can be thought of as having the same type of facilities where a user will define how many and what type of value it will store, just in a slightly different way. :)

Upvotes: 2

TEH EMPRAH
TEH EMPRAH

Reputation: 2058

I would use enums as a useful mapping instrument, avoiding multiple if-else provided that some methods are implemented.

public enum Mapping {

    ONE("1"),
    TWO("2");

    private String label;

    private Mapping(String label){
        this.label = label;
    }

    public static Mapping by(String label) {

        for(Mapping m: values() {
            if(m.label.equals(label)) return m;
        }

        return null;
    }

}

So the method by(String label) allows you to get the Enumerated value by non-enumerated. Further, one can invent mapping between 2 enums. Could also try '1 to many' or 'many to many' in addition to 'one to one' default relation

In the end, enum is a Java class. So you can have main method inside it, which might be useful when needing to do some mapping operations on args right away.

Upvotes: 0

Ad Infinitum
Ad Infinitum

Reputation: 3696

It is useful to know that enums are just like the other classes with Constant fields and a private constructor.

For example,

public enum Weekday
{
  MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
} 

The compiler compiles it as follows;

class Weekday extends Enum
{
  public static final Weekday MONDAY  = new Weekday( "MONDAY",   0 );
  public static final Weekday TUESDAY = new Weekday( "TUESDAY ", 1 );
  public static final Weekday WEDNESDAY= new Weekday( "WEDNESDAY", 2 );
  public static final Weekday THURSDAY= new Weekday( "THURSDAY", 3 );
  public static final Weekday FRIDAY= new Weekday( "FRIDAY", 4 );
  public static final Weekday SATURDAY= new Weekday( "SATURDAY", 5 );
  public static final Weekday SUNDAY= new Weekday( "SUNDAY", 6 );

  private Weekday( String s, int i )
  {
    super( s, i );
  }

  // other methods...
}

Upvotes: 15

Premraj
Premraj

Reputation: 74551

enum means enumeration i.e. mention (a number of things) one by one.

An enum is a data type that contains fixed set of constants.

OR

An enum is just like a class, with a fixed set of instances known at compile time.

For example:

public class EnumExample {
    interface SeasonInt {
        String seasonDuration();
    }

    private enum Season implements SeasonInt {
        // except the enum constants remaining code looks same as class
        // enum constants are implicitly public static final we have used all caps to specify them like Constants in Java
        WINTER(88, "DEC - FEB"), SPRING(92, "MAR - JUN"), SUMMER(91, "JUN - AUG"), FALL(90, "SEP - NOV");

        private int days;
        private String months;

        Season(int days, String months) { // note: constructor is by default private 
            this.days = days;
            this.months = months;
        }

        @Override
        public String seasonDuration() {
            return this+" -> "+this.days + "days,   " + this.months+" months";
        }

    }
    public static void main(String[] args) {
        System.out.println(Season.SPRING.seasonDuration());
        for (Season season : Season.values()){
            System.out.println(season.seasonDuration());
        }

    }
}

Advantages of enum:

  • enum improves type safety at compile-time checking to avoid errors at run-time.
  • enum can be easily used in switch
  • enum can be traversed
  • enum can have fields, constructors and methods
  • enum may implement many interfaces but cannot extend any class because it internally extends Enum class

for more

Upvotes: 15

BradB
BradB

Reputation: 21

In my experience I have seen Enum usage sometimes cause systems to be very difficult to change. If you are using an Enum for a set of domain-specific values that change frequently, and it has a lot of other classes and components that depend on it, you might want to consider not using an Enum.

For example, a trading system that uses an Enum for markets/exchanges. There are a lot of markets out there and it's almost certain that there will be a lot of sub-systems that need to access this list of markets. Every time you want a new market to be added to your system, or if you want to remove a market, it's possible that everything under the sun will have to be rebuilt and released.

A better example would be something like a product category type. Let's say your software manages inventory for a department store. There are a lot of product categories, and many reasons why this list of categories could change. Managers may want to stock a new product line, get rid of other product lines, and possibly reorganize the categories from time to time. If you have to rebuild and redeploy all of your systems simply because users want to add a product category, then you've taken something that should be simple and fast (adding a category) and made it very difficult and slow.

Bottom line, Enums are good if the data you are representing is very static over time and has a limited number of dependencies. But if the data changes a lot and has a lot of dependencies, then you need something dynamic that isn't checked at compile time (like a database table).

Upvotes: 2

CodeToLife
CodeToLife

Reputation: 4131

As for me to make the code readable in future the most useful aplyable case of enumeration is represented in next snippet:

public enum Items {
    MESSAGES, CHATS, CITY_ONLINE, FRIENDS, PROFILE, SETTINGS, PEOPLE_SEARCH, CREATE_CHAT
}

@Override
public boolean onCreateOptionsMenu(Menu menuPrm) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menuPrm);
    View itemChooserLcl;
    for (int i = 0; i < menuPrm.size(); i++) {
        MenuItem itemLcl  = menuPrm.getItem(i);
            itemChooserLcl = itemLcl.getActionView();
            if (itemChooserLcl != null) {
                 //here Im marking each View' tag by enume values:
                itemChooserLcl.setTag(Items.values()[i]);
                itemChooserLcl.setOnClickListener(drawerMenuListener);
            }
        }
    return true;
}
private View.OnClickListener drawerMenuListener=new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Items tagLcl= (Items) v.getTag();
        switch (tagLcl){
            case MESSAGES: ;
            break;
            case CHATS : ;
            break;
            case CITY_ONLINE : ;
            break;
            case FRIENDS : ;
            break;
            case  PROFILE: ;
            break;
            case  SETTINGS: ;
            break;
            case  PEOPLE_SEARCH: ;
            break;
            case  CREATE_CHAT: ;
            break;
        }
    }
};

Upvotes: 1

djangofan
djangofan

Reputation: 29669

What gave me the Ah-Ha moment was this realization: that Enum has a private constructor only accessible via the public enumeration:

enum RGB {
    RED("Red"), GREEN("Green"), BLUE("Blue");

    public static final String PREFIX = "color ";

    public String getRGBString() {
        return PREFIX + color;
    }

    String color;

    RGB(String color) {
        this.color = color;
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        String c = RGB.RED.getRGBString();
        System.out.print("Hello " + c);
    }
}

Upvotes: 1

Gene
Gene

Reputation: 46960

Why use any programming language feature? The reason we have languages at all is for

  1. Programmers to efficiently and correctly express algorithms in a form computers can use.
  2. Maintainers to understand algorithms others have written and correctly make changes.

Enums improve both likelihood of correctness and readability without writing a lot of boilerplate. If you are willing to write boilerplate, then you can "simulate" enums:

public class Color {
    private Color() {} // Prevent others from making colors.
    public static final Color RED = new Color();
    public static final Color AMBER = new Color();
    public static final Color GREEN = new Color();
}

Now you can write:

Color trafficLightColor = Color.RED;

The boilerplate above has much the same effect as

public enum Color { RED, AMBER, GREEN };

Both provide the same level of checking help from the compiler. Boilerplate is just more typing. But saving a lot of typing makes the programmer more efficient (see 1), so it's a worthwhile feature.

It's worthwhile for at least one more reason, too:

Switch statements

One thing that the static final enum simulation above does not give you is nice switch cases. For enum types, the Java switch uses the type of its variable to infer the scope of enum cases, so for the enum Color above you merely need to say:

Color color = ... ;
switch (color) {
    case RED:
        ...
        break;
}

Note it's not Color.RED in the cases. If you don't use enum, the only way to use named quantities with switch is something like:

public Class Color {
    public static final int RED = 0;
    public static final int AMBER = 1;
    public static final int GREEN = 2;
}

But now a variable to hold a color must have type int. The nice compiler checking of the enum and the static final simulation is gone. Not happy.

A compromise is to use a scalar-valued member in the simulation:

public class Color {
    public static final int RED_TAG = 1;
    public static final int AMBER_TAG = 2;
    public static final int GREEN_TAG = 3;

    public final int tag;

    private Color(int tag) { this.tag = tag; } 
    public static final Color RED = new Color(RED_TAG);
    public static final Color AMBER = new Color(AMBER_TAG);
    public static final Color GREEN = new Color(GREEN_TAG);
}

Now:

Color color = ... ;
switch (color.tag) {
    case Color.RED_TAG:
        ...
        break;
}

But note, even more boilerplate!

Using an enum as a singleton

From the boilerplate above you can see why an enum provides a way to implement a singleton. Instead of writing:

public class SingletonClass {
    public static final void INSTANCE = new SingletonClass();
    private SingletonClass() {}

    // all the methods and instance data for the class here
}

and then accessing it with

SingletonClass.INSTANCE

we can just say

public enum SingletonClass {
    INSTANCE;

    // all the methods and instance data for the class here
}

which gives us the same thing. We can get away with this because Java enums are implemented as full classes with only a little syntactic sugar sprinkled over the top. This is again less boilerplate, but it's non-obvious unless the idiom is familiar to you. I also dislike the fact that you get the various enum functions even though they don't make much sense for the singleton: ord and values, etc. (There's actually a trickier simulation where Color extends Integer that will work with switch, but it's so tricky that it even more clearly shows why enum is a better idea.)

Thread safety

Thread safety is a potential problem only when singletons are created lazily with no locking.

public class SingletonClass {
    private static SingletonClass INSTANCE;
    private SingletonClass() {}
    public SingletonClass getInstance() {
        if (INSTANCE == null) INSTANCE = new SingletonClass();
        return INSTANCE;
    }

    // all the methods and instance data for the class here
}

If many threads call getInstance simultaneously while INSTANCE is still null, any number of instances can be created. This is bad. The only solution is to add synchronized access to protect the variable INSTANCE.

However, the static final code above does not have this problem. It creates the instance eagerly at class load time. Class loading is synchronized.

The enum singleton is effectively lazy because it's not initialized until first use. Java initialization is also synchronized, so multiple threads can't initialize more than one instance of INSTANCE. You're getting a lazily initialized singleton with very little code. The only negative is the the rather obscure syntax. You need to know the idiom or thoroughly understand how class loading and initialization work to know what's happening.

Upvotes: 154

Rahul Prajapat
Rahul Prajapat

Reputation: 35

Java lets you restrict variable to having one of only a few predefined values - in other words, one value from an enumerated list. Using enums can help to reduce bug's in your code. Here is an example of enums outside a class:

enums coffeesize{BIG , HUGE , OVERWHELMING }; 
//This semicolon is optional.

This restricts coffeesize to having either: BIG , HUGE , or OVERWHELMING as a variable.

Upvotes: 2

abishkar bhattarai
abishkar bhattarai

Reputation: 7641

Enum inherits all the methods of Object class and abstract class Enum. So you can use it's methods for reflection, multithreading, serilization, comparable, etc. If you just declare a static constant instead of Enum, you can't. Besides that, the value of Enum can be passed to DAO layer as well.

Here's an example program to demonstrate.

public enum State {

    Start("1"),
    Wait("1"),
    Notify("2"),
    NotifyAll("3"),
    Run("4"),
    SystemInatilize("5"),
    VendorInatilize("6"),
    test,
    FrameworkInatilize("7");

    public static State getState(String value) {
        return State.Wait;
    }

    private String value;
    State test;

    private State(String value) {
        this.value = value;
    }

    private State() {
    }

    public String getValue() {
        return value;
    }

    public void setCurrentState(State currentState) {
        test = currentState;
    }

    public boolean isNotify() {
        return this.equals(Notify);
    }
}

public class EnumTest {

    State test;

    public void setCurrentState(State currentState) {
        test = currentState;
    }

    public State getCurrentState() {
        return test;
    }

    public static void main(String[] args) {
        System.out.println(State.test);
        System.out.println(State.FrameworkInatilize);
        EnumTest test=new EnumTest();
        test.setCurrentState(State.Notify);
        test. stateSwitch();
    }

    public void stateSwitch() {
        switch (getCurrentState()) {
        case Notify:
            System.out.println("Notify");
            System.out.println(test.isNotify());
            break;
        default:
            break;
        }
    }
}

Upvotes: 7

sleske
sleske

Reputation: 83577

You should always use enums when a variable (especially a method parameter) can only take one out of a small set of possible values. Examples would be things like type constants (contract status: "permanent", "temp", "apprentice"), or flags ("execute now", "defer execution").

If you use enums instead of integers (or String codes), you increase compile-time checking and avoid errors from passing in invalid constants, and you document which values are legal to use.

BTW, overuse of enums might mean that your methods do too much (it's often better to have several separate methods, rather than one method that takes several flags which modify what it does), but if you have to use flags or type codes, enums are the way to go.

As an example, which is better?

/** Counts number of foobangs.
 * @param type Type of foobangs to count. Can be 1=green foobangs,
 * 2=wrinkled foobangs, 3=sweet foobangs, 0=all types.
 * @return number of foobangs of type
 */
public int countFoobangs(int type)

versus

/** Types of foobangs. */
public enum FB_TYPE {
 GREEN, WRINKLED, SWEET, 
 /** special type for all types combined */
 ALL;
}

/** Counts number of foobangs.
 * @param type Type of foobangs to count
 * @return number of foobangs of type
 */
public int countFoobangs(FB_TYPE type)

A method call like:

int sweetFoobangCount = countFoobangs(3);

then becomes:

int sweetFoobangCount = countFoobangs(FB_TYPE.SWEET);

In the second example, it's immediately clear which types are allowed, docs and implementation cannot go out of sync, and the compiler can enforce this. Also, an invalid call like

int sweetFoobangCount = countFoobangs(99);

is no longer possible.

Upvotes: 777

Vishal Verma
Vishal Verma

Reputation: 982

There are many answers here, just want to point two specific ones:

1) Using as constants in Switch-case statement. Switch case won't allow you to use String objects for case. Enums come in handy. More: http://www.javabeat.net/2009/02/how-to-use-enum-in-switch/

2) Implementing Singleton Design Pattern - Enum again, comes to rescue. Usage, here: What is the best approach for using an Enum as a singleton in Java?

Upvotes: 1

happybuddha
happybuddha

Reputation: 1358

So far, I have never needed to use enums. I have been reading about them since they were introduced in 1.5 or version tiger as it was called back in the day. They never really solved a 'problem' for me. For those who use it (and I see a lot of them do), am sure it definitely serves some purpose. Just my 2 quid.

Upvotes: 0

afsantos
afsantos

Reputation: 5208

Enums enumerate a fixed set of values, in a self-documenting way.
They make your code more explicit, and also less error-prone.

Why not using String, or int, instead of Enum, for constants?

  1. The compiler won't allow typos, neither values out of the fixed set, as enums are types by themselves. Consequences:
    • You won't have to write a pre-condition (or a manual if) to assure your argument is in the valid range.
    • The type invariant comes for free.
  2. Enums can have behaviour, just as any other class.
  3. You would probably need a similar amount of memory to use Strings, anyway (this depends on the complexity of the Enum).

Moreover, each of the Enum's instances is a class, for which you can define its individual behaviour.

Plus, they assure thread safety upon creation of the instances (when the enum is loaded), which has seen great application in simplifying the Singleton Pattern.

This blog illustrates some of its applications, such as a State Machine for a parser.

Upvotes: 15

Rafa
Rafa

Reputation: 2368

In my opinion, all the answers you got up to now are valid, but in my experience, I would express it in a few words:

Use enums if you want the compiler to check the validity of the value of an identifier.

Otherwise, you can use strings as you always did (probably you defined some "conventions" for your application) and you will be very flexible... but you will not get 100% security against typos on your strings and you will realize them only in runtime.

Upvotes: 4

sErVerdevIL
sErVerdevIL

Reputation: 263

Apart from all said by others.. In an older project that I used to work for, a lot of communication between entities(independent applications) was using integers which represented a small set. It was useful to declare the set as enum with static methods to get enum object from value and viceversa. The code looked cleaner, switch case usability and easier writing to logs.

enum ProtocolType {
    TCP_IP (1, "Transmission Control Protocol"), 
    IP (2, "Internet Protocol"), 
    UDP (3, "User Datagram Protocol");

    public int code;
    public String name;

    private ProtocolType(int code, String name) {
        this.code = code;
        this.name = name;
    }

    public static ProtocolType fromInt(int code) {
    switch(code) {
    case 1:
        return TCP_IP;
    case 2:
        return IP;
    case 3:
        return UDP;
    }

    // we had some exception handling for this
    // as the contract for these was between 2 independent applications
    // liable to change between versions (mostly adding new stuff)
    // but keeping it simple here.
    return null;
    }
}

Create enum object from received values (e.g. 1,2) using ProtocolType.fromInt(2) Write to logs using myEnumObj.name

Hope this helps.

Upvotes: 9

Steve
Steve

Reputation: 1489

ENum stands for "Enumerated Type". It is a data type having a fixed set of constants which you define yourself.

Upvotes: 4

orangepips
orangepips

Reputation: 9981

Something none of the other answers have covered that make enums particularly powerful are the ability to have template methods. Methods can be part of the base enum and overridden by each type. And, with the behavior attached to the enum, it often eliminates the need for if-else constructs or switch statements as this blog post demonstrates - where enum.method() does what originally would be executed inside the conditional. The same example also shows the use of static imports with enums as well producing much cleaner DSL like code.

Some other interesting qualities include the fact that enums provide implementation for equals(), toString() and hashCode() and implement Serializable and Comparable.

For a complete rundown of all that enums have to offer I highly recommend Bruce Eckel's Thinking in Java 4th edition which devotes an entire chapter to the topic. Particularly illuminating are the examples involving a Rock, Paper, Scissors (i.e. RoShamBo) game as enums.

Upvotes: 34

CoolBeans
CoolBeans

Reputation: 20800

From Java documents -

You should use enum types any time you need to represent a fixed set of constants. That includes natural enum types such as the planets in our solar system and data sets where you know all possible values at compile time—for example, the choices on a menu, command line flags, and so on.

A common example is to replace a class with a set of private static final int constants (within reasonable number of constants) with an enum type. Basically if you think you know all possible values of "something" at compile time you can represent that as an enum type. Enums provide readability and flexibility over a class with constants.

Few other advantages that I can think of enum types. They is always one instance of a particular enum class (hence the concept of using enums as singleton arrives). Another advantage is you can use enums as a type in switch-case statement. Also you can use toString() on the enum to print them as readable strings.

Upvotes: 27

Related Questions