There's more to Java Enums
If you find yourself using "switch" or "if-else" a lot with your enums, then you're missing out on one important feature.
Java's enums, being objects themselves, can have state and behavior.
Consider the following example.
public enum Coin {
PENNY,
NICKEL,
DIME,
QUARTER,
HALF_DOLLAR,
DOLLAR
}
You might be tempted to do the following:
public long getValueInCents(Coin coin) {
switch (coin) {
case PENNY: return 1;
case NICKEL: return 5;
case DIME: return 10;
case QUARTER: return 25;
case HALF_DOLLAR: return 50;
case DOLLAR: return 100;
}
}
public long addTwoCoins(Coin coin1, Coin coin2) {
return getValueInCents(coin1) + getValueInCents(coin2);
}
Nothing wrong with that. However, if you start adding more and more methods around them, then you could end up with a lot of if-else or switch statements. Say, your application is a virtual vending machine, and it only accepts certain coins. You might have a method like this:
public boolean isAccepted(Coin coin) {
return coin == Coin.DIME || coin == Coin.QUARTER;
}
Again, nothing wrong with that. But what if you could encapsulate all of the above into the enums?
Here's the same Coin enum after the makeover.
public enum Coin {
PENNY(1, false),
NICKEL(5, false),
DIME(10, true),
QUARTER(25, true),
HALF_DOLLAR(50, false),
DOLLAR(100, false);
// enums can have state; these are set via the constructor
private long valueInCents;
private boolean isAccepted;
private Coin(long valueInCents, boolean isAccepted) {
this.valueInCents = valueInCents;
this.isAccepted = isAccepted;
}
// enums can also have behavior
public long getValueInCents() {
return valueInCents;
}
public boolean isAccepted() {
return isAccepted;
}
public long add(Coin anotherCoin) {
return this.valueInCents + anotherCoin.valueInCents;
}
}
Code that uses this new enum implementation simply has to call any of the public methods, e.g.:
public void attemptCoins(Coin coin1, Coin coin2) {
if (coin1.isAccepted() && coin2.isAccepted()) {
long totalValue = coin1.add(coin2);
// rest of method here...
} else {
throw new RuntimeException("One or both coins are not accepted!");
}
}
Each enum value can also override methods as needed. Here's a very contrived example where the DOLLAR enum throws an exception when add() is called with anything more than 25 cents. Perhaps because the maximum value supported by the application is $1.25, ha! Told you it was contrived.
public enum Coin {
PENNY(1, false),
NICKEL(5, false),
DIME(10, true),
QUARTER(25, true),
HALF_DOLLAR(50, false),
DOLLAR(100, false) {
@Override
public long add(Coin anotherCoin) {
if (anotherCoin.valueInCents <= 25) {
return super.add(anotherCoin);
}
throw new ValueOverflowException();
}
}
// enums can have state; these are set via the constructor
private long valueInCents;
private boolean isAccepted;
private Coin(long valueInCents, boolean isAccepted) {
this.valueInCents = valueInCents;
this.isAccepted = isAccepted;
}
// enums can also have behavior
public long getValueInCents() {
return valueInCents;
}
public boolean isAccepted() {
return isAccepted;
}
public long add(Coin anotherCoin) {
return this.valueInCents + anotherCoin.valueInCents;
}
}