An enumerated type is basically a data type that lets you describe each member of a type in a more readable and reliable way.
Here is a simple example to explain why:
Assuming you are writing a method that has something to do with seasons:
The int enum pattern
First, you declared some int static constants to represent each season.
public static final int SPRING = 0;
public static final int SUMMER = 1;
public static final int FALL = 2;
public static final int WINTER = 2;
Then, you declared a method to print name of the season into the console.
public void printSeason(int seasonCode) {
String name = "";
if (seasonCode == SPRING) {
name = "Spring";
}
else if (seasonCode == SUMMER) {
name = "Summer";
}
else if (seasonCode == FALL) {
name = "Fall";
}
else if (seasonCode == WINTER) {
name = "Winter";
}
System.out.println("It is " + name + " now!");
}
So, after that, you can print a season name like this.
printSeason(SPRING);
printSeason(WINTER);
This is a pretty common (but bad) way to do different things for different types of members in a class. However, since these code involves integers, so you can also call the method like this without any problems.
printSeason(0);
printSeason(1);
or even like this
printSeason(x - y);
printSeason(10000);
The compiler will not complain because these method calls are valid, and your printSeason
method can still work.
But something is not right here. What does a season code of 10000
supposed to mean? What if x - y
results in a negative number? When your method receives an input that has no meaning and is not supposed to be there, your program knows nothing about it.
You can fix this problem, for example, by adding an additional check.
...
else if (seasonCode == WINTER) {
name = "Winter";
}
else {
throw new IllegalArgumentException();
}
System.out.println(name);
Now the program will throw a RunTimeException
when the season code is invalid. However, you still need to decide how you are going to handle the exception.
By the way, I am sure you noticed the code of FALL
and WINTER
are both 2, right?
You should get the idea now. This pattern is brittle. It makes you write condition checks everywhere. If you're making a game, and you want to add an extra season into your imaginary world, this pattern will make you go though all the methods that do things by season, and in most case you will forget some of them.
You might think class inheritance is a good idea for this case. But we just need some of them and no more.
That's when enum
comes into play.
Use enum
type
In Java, enum
types are classes that export one instance for each enumeration constant via a public static final field.
Here you can declare four enumeration constants: SPRING, SUMMER, FALL, WINTER
. Each has its own name
.
public enum Season {
SPRING("Spring"), SUMMER("Summer"), FALL("Fall"), WINTER("Winter");
private String name;
Season(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Now, back to the method.
public void printSeason(Season season) {
System.out.println("It is " + season.getName() + " now!");
}
Instead of using int
, you can now use Season
as input. Instead of a condition check, you can tell Season
to give you its name.
This is how you use this method now:
printSeason(Season.SPRING);
printSeason(Season.WINTER);
printSeason(Season.WHATEVER); <-- compile error
You will get a compile-time error when you use an incorrect input, and you're guaranteed to get a non-null singleton reference of Season
as long as the program compiles.
When we need an additional season, we simply add another constant in Season
and no more.
public enum Season {
SPRING("Spring"), SUMMER("Summer"), FALL("Fall"), WINTER("Winter"),
MYSEASON("My Season");
...
Whenever you need a fixed set of constants, enum
can be a good choice (but not always). It's a more readable, more reliable and more powerful solution.