Here is the original code:
public class FruitGrower {
public void growAFruit(String type) {
if ("wtrmln".equals(type)) {
//do watermelon growing stuff
} else if ("ppl".equals(type)) {
//do apple growing stuff
} else if ("pnppl".equals(type)) {
//do pineapple growing stuff
} else if ("rng".equals(type)) {
//do orange growing stuff
} else {
// do other fruit growing stuff
}
}
}
This is how I changed it:
public class FruitGrower {
enum Fruits {
WATERMELON {
@Override
void growAFruit() {
//do watermelon growing stuff
}
},
APPLE {
@Override
void growAFruit() {
//do apple growing stuff
}
},
PINEAPPLE {
@Override
void growAFruit() {
//do pineapple growing stuff
}
},
ORANGE {
@Override
void growAFruit() {
//do orange growing stuff
}
},
OTHER {
@Override
void growAFruit() {
// do other fruit growing stuff
}
};
static void grow(String type) {
if ("wtrmln".equals(type)) {
WATERMELON.growAFruit();
} else if ("ppl".equals(type)) {
APPLE.growAFruit();
} else if ("pnppl".equals(type)) {
PINEAPPLE.growAFruit();
} else if ("rng".equals(type)) {
ORANGE.growAFruit();
} else {
OTHER.growAFruit();
}
};
abstract void growAFruit();
}
public void growAFruit(String type) {
Fruits.grow(type);
}
}
I see that enums
code is longer and may be not as clear as if-else
code, but I believe it's better, could someone tell me, why I'm wrong (or maybe I'm not)?
UPD - changed source code to be more problem-specific. I'll rephrase the question: are there any concerns about using enum instead of if-else?
You've already got good answers about improving your use of Enums. As for why they're better than string constants:
I think the biggest benefit is compile-time error checking. If I were to call growAFruit("watermelon")
, the compiler would have no idea anything was wrong. And since I've spelled it correctly, it's not going to stand out as a mistake when you're viewing the code. But if I were to WATERMELEN.growAFruit()
, the compiler can tell you immediately that I've misspelled it.
You also get to define growAFruit
as a bunch of simple, easy-to-read methods, instead of a big block of if
-then
-else
s. This becomes even more apparent when you have a few dozen fruits, or when you start adding harvestAFruit()
, packageAFruit()
, sellAFruit()
, etc. Without enums you'd be copying your big if-else block all over, and if you forgot to add a case it would fall through to the default case or do nothing, while with enums the compiler can tell you that the method hasn't been implemented.
Even more compiler-checking goodness: If you also have a growVegetable
method and the related string constants, there's nothing stopping you from calling growVegetable("pineapple")
or growFruit("peas")
. If you've got a "tomato"
constant, the only way to know if you consider it a fruit or a vegetable is to read the source code of the relevant methods. Once again, with enums the compiler can tell you right away if you've done something wrong.
Another benefit is that it groups related constants together and gives them a proper home. The alternative being a bunch of public static final
fields thrown in some class that happens to use them, or stuck a interface of constants. The interface full of constants doesn't even make sense because if that's all you need defining the enum is much easier than writing out the interface. Also, in classes or interfaces there is the possibility to accidentally use the same value for more than one constant.
They're also iterable. To get all the values of an enum you can just call Fruit.values()
, whereas with constants you'd have to create and populate your own array. Or if just using literals as in your example, there is no authoritive list of valid values.
Bonus Round: IDE Support
The main reason not to use an enum would be if you don't know all the possible values at compile time (i.e. you need to add more values while the program is running). In that case you might want to define them as a class heirarchy. Also, don't throw a bunch of unrelated constants into an enum and call it a day. There should be some sort of common thread connecting the values. You can always make multiple enums if that's more appropriate.