I am an almost-graduating computer science student, and throughout my coding career, I've found very few instances where enumerations, except for canonical cases such as representing the faces of a standard deck of cards, are used.
Do you know of any clever ways that enums are used in everyday coding?
Why are enumerations so important and in what situations should one be able to identify that building an enumeration is the best approach?
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").
Enumerations serve the purpose of representing a group of named constants in a programming language.
An enumeration is used in any programming language to define a constant set of values. For example, the days of the week can be defined as an enumeration and used anywhere in the program. In C#, the enumeration is defined with the help of the keyword 'enum'.
In C++ programming, enum or enumeration is a data type consisting of named values like elements, members, etc., that represent integral constants. It provides a way to define and group integral constants. It also makes the code easy to maintain and less complex.
These are the main arguments for enum
, EnumMap
, and EnumSet
by short examples.
enum
As of Java 6, java.util.Calendar
is an example of a messy class that could've benefited a lot from using enum
(among other improvements).
Currently Calendar
defines the following constants (among many others):
// int constant antipattern from java.util.Calendar
public static final int JANUARY = 0;
public static final int FEBRUARY = 1;
...
public static final int SUNDAY = 1;
public static final int MONDAY = 2;
...
These are all int
, even though they obviously represent different conceptual entities.
The following are some serious consequences:
MONDAY = 0;
, SUNDAY = 0;
, then we have MONDAY == SUNDAY
int
:
setMonth(JANUARY)
, but we can also setMonth(THURSDAY)
or setMonth(42)
set(int,int,int,int,int,int)
(a real method!) does!By contrast, we could have something like this instead:
// Hypothetical enums for a Calendar library
enum Month {
JANUARY, FEBRUARY, ...
}
enum DayOfWeek {
SUNDAY, MONDAY, ...
}
Now we never have to worry about MONDAY == SUNDAY
(it can never happen!), and since Month
and DayOfWeek
are different types, setMonth(MONDAY)
does not compile.
Additionally, here are some before-and-after codes:
// BEFORE with int constants
for (int month = JANUARY; month <= DECEMBER; month++) {
...
}
Here we're making all sorts of assumptions, e.g. JANUARY + 1 == FEBRUARY
, etc. On the other hand, the enum
counterpart is both more concise, more readable, and makes less assumptions (and therefore less chance for bugs):
// AFTER with enum
for (Month month : Month.values()) {
...
}
In Java, enum
is a class
that has many special properties, but a class
nonetheless, allowing you to define instance methods and fields if necessary.
Consider the following example:
// BEFORE: with int constants
public static final int NORTH = 0;
public static final int EAST = 1;
public static final int SOUTH = 2;
public static final int WEST = 3;
public static int degreeFor(int direction) {
return direction * 90; // quite an assumption!
// must be kept in-sync with the int constants!
}
//...
for (int dir = NORTH; dir <= WEST; dir++) {
... degreeFor(dir) ...
}
On the other hand, with enum
you can write something like this:
enum Direction {
NORTH(0), EAST(90), SOUTH(180), WEST(270);
// so obvious! so easy to read! so easy to write! so easy to maintain!
private final int degree;
Direction(int degree) { this.degree = degree; }
public int getDegree() { return degree; }
}
//...
for (Direction dir : Direction.values()) {
... dir.getDegree() ...
}
Consider the following example:
static int apply(int op1, int op2, int operator) {
switch (operator) {
case PLUS : return op1 + op2;
case MINUS : return op1 - op2;
case ...
default: throw new IllegalArgumentException("Unknown operator!");
}
}
As shown in previous example, enum
in Java can have instance methods, but not only that but each constant can have its own specific @Override
as well. This is shown in the following code:
enum Operator {
PLUS { int apply(int op1, int op2) { return op1 + op2; } },
MINUS { int apply(int op1, int op2) { return op1 - op2; } },
...
;
abstract int apply(int op1, int op2);
}
EnumMap
Here's a quote from Effective Java 2nd Edition:
Never derive a value associated with an
enum
from itsordinal()
; store it in an instance field instead. (Item 31: Use instance fields instead of ordinals) It is rarely appropriate to use ordinals to index arrays: useEnumMap
instead. The general principle is that application programmers should rarely, if ever, useEnum.ordinal
. (Item 33: UseEnumMap
instead of ordinal indexing)
Essentially where as before you may have something like this:
// BEFORE, with int constants and array indexing
Employee[] employeeOfTheMonth = ...
employeeOfTheMonth[JANUARY] = jamesBond;
Now you can have:
// AFTER, with enum and EnumMap
Map<Month, Employee> employeeOfTheMonth = ...
employeeOfTheMonth.put(Month.JANUARY, jamesBond);
EnumSet
Power of two int
constants are often used e.g. in C++ to denote bit sets. This relies on bitwise operations. An example may look something like this:
public static final int BUTTON_A = 1;
public static final int BUTTON_B = 2;
public static final int BUTTON_X = 4;
public static final int BUTTON_Y = 8;
int buttonState = BUTTON_A | BUTTON_X; // A & X are pressed!
if ((buttonState & BUTTON_B) != 0) { // B is pressed...
...
}
With enum
and EnumSet
, this can look something like this:
enum Button {
A, B, X, Y;
}
Set<Button> buttonState = EnumSet.of(Button.A, Button.X); // A & X are pressed!
if (buttonState.contains(Button.B)) { // B is pressed...
...
}
enum
instead of int
constantsEnumSet
instead of bit fieldsEnumMap
instead of ordinal indexingordinal()
, however...EnumSet
!What you would define as String
/ int
constants before Java 1.5, you should now define as enums. For example, instead of having:
public class StatusConstants {
public int ACTIVE = 1;
public int SUSPENDED = 2;
public int TEMPORARY_INACTIVE = 3;
public int NOT_CONFIRMED = 4;
}
You now have a safer and more developer-friendly:
public enum Status {
ACTIVE, SUSPENDED, TEMPORARY_INACTIVE, NOT_CONFIRMED
}
Same goes for anything that has more than one options, like statuses, street types (str., boul., rd., etc), user access levels (administrator, moderator, regular user), etc. etc.
Check this for more examples and explanations.
Consider some simple code:
without enums:
int OPT_A_ON = 1;
int OPT_A_OFF = 0;
int OPT_B_ON = 1;
int OPT_B_OFF = 0;
SetOption(OPT_A_ON, OPT_B_OFF); // Declaration: SetOption(int, int)
That look fine, right? Except SetOptions() wants Option B first and then Option A. This will go through the compiler just fine, but when run, sets the options backwards.
Now, with enums:
enum OptA {On =1, Off = 0};
enum OptB {On =1, Off = 0};
SetOption(OptA.On, OptB.Off);// Declaration: SetOption(OptB, OptA)
Now we make the same error, but this time, since enums are different types, the mistake is caught by the compiler.
(NOTE: I'm not really a Java programmer, so please forgive minor syntax errors)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With