TL;DR
Enums constructors have exactly the same purpose as constructors in classes, initialize values. Enums are nothing more than a specific type of class.
Enums are classes
The first thing to definitely understand Enums is that they are nothing more than classes with some specific characteristics and "syntactic sugar".
Let’s see, the question has the following example of Enum:
public enum Genero
{
MASCULINO(1), FEMININO(2);
public int codigo;
private Genero(int codigo)
{
this.codigo = codigo;
}
}
We could easily rewrite the above example as a normal class:
public class EnumGenero {
public static final EnumGenero MASCULINO = new EnumGenero(1), FEMININO = new EnumGenero(2);
public int codigo;
private EnumGenero(int codigo)
{
this.codigo = codigo;
}
}
And the use is practically equal:
EnumGenero masculino1 = EnumGenero.MASCULINO;
Genero masculino2 = Genero.MASCULINO;
Important points:
- Enums constants are nothing more than static attributes. See in the example how I introduce the class into constants. It’s the same thing with Enum, the difference is that you don’t need to put the access modifiers or the
new
, but the behavior is exactly the same.
- Enums are instantiated exactly like classes. As I said in the previous item, the difference is that the
new
is implicit in the simplified Enum syntax.
- The builder of Enum is always
private
And you don’t have to put this modifier in, it’s redundant. In the case of the class, it depends on you placing it there to prevent other instances from being created.
Enums vs. Classes
Is there any difference between using Enums and classes like the one I put above? Let’s consider the differences for the above example.
About the Enum:
- Can use with
switch
and some Ides warn in case you forget to put some value.
- Simplified syntax that gives certain guarantees, such as that there will be no instances other than predefined constants.
- Auxiliary methods such as
name()
, ordinal()
, valueOf()
and values()
.
About the class:
- More flexibility, allows inheritance and other constructions, although this is usually not recommended unless there is a very strong reason.
- Disadvantage of you having to manually add all access modifiers in addition to the instantiation of each constant.
- It does not have Enum auxiliary methods by default, but can be implemented, although not in a very simple and safe way.
Comments on the implementation of the Enum
Encapsulation
Your Enum may have the attribute codigo
accessed via getter
:
public enum Genero {
MASCULINO(1), FEMININO(2);
private int codigo;
private Genero(int codigo) {
this.codigo = codigo;
}
public int getCodigo() {
return codigo;
}
}
Is there any need for this? Technically not.
Although it is generally desirable to encapsulate the attributes so as not to allow direct access via external code, this argument is not as strong when we speak of constants.
The value does not change and there is no strong reason in this specific case to encapsulate an attribute that has very low probability of changing in the future.
However, the strongest reasons to use a getter
is to maintain consistency (it is bad to work in a system where now attributes are exposed, sometimes they are not) and to enable internal refactoring in the future, even if this is not visible now.
A situation where I nay recommends using encapsulation is in internal classes where the use of the value is private. Example:
public class ProcessaAlgoComGenero {
public enum Genero {
MASCULINO(1), FEMININO(2);
private int codigo;
Genero(int codigo) {
this.codigo = codigo;
}
}
public void processaGenero(Genero g) {
System.out.println(g.codigo);
}
}
And the call goes like this:
new ProcessaAlgoComGenero().processaGenero(ProcessaAlgoComGenero.Genero.MASCULINO);
Note that the attribute codigo
is only accessible within the class ProcessaAlgoComGenero
. Encapsulating an attribute used only internally is unnecessary.
Retrieving values by code
It is common when we add attributes to Enum values we need to recover constants based on that value.
While to recover the constant based on the name using the ready method valueOf()
, we have to build the other method ourselves.
So if at any time you need to retrieve the Enum by codigo
, can do this:
public static Genero ofCode(int codigo) {
for (Genero g : values()) {
if (g.codigo == codigo) {
return g;
}
}
return null; //ou lança uma exceção
}
Note that the method ofCode
traverse all Enum values through the array returned by values()
and search for the constant with the codigo
to be recovered.
The advantage of this code instead of a if
or switch
is that you can reuse it for any situation, including other Enums, with a minimum of change.
You could just do it like this:
public static Genero ofCode(int codigo) {
if (MASCULINO.codigo == codigo) return MASCULINO;
if (FEMININO.codigo == codigo) return FEMININO;
return null; //ou lança uma exceção
}
But in this case for each One you would have to rewrite everything.
If there are too many constants and the running time is a concern, you can use a map to make the search time constant.
First you would need to initialize the map as soon as Enum is initialized. Just add this in Enum:
static Map<Integer, Genero> cache = new HashMap<>();
static {
for (Genero g : values()) {
cache.put(g.codigo, g);
}
}
And then the method ofCode
is trivial and efficient:
public static Genero ofCode(int codigo) {
return cache.get(codigo);
}
Considerations
Using Enum is good, facilitates coding and makes code safer against misconceptions and even against "smart-ass programmers".
Enums are flexible as classes, although with several other restrictions. As seen in the example above, it is possible to create complex constructions within Enums. However, use this only in cases where it is really necessary, otherwise you are adding complexity and unnecessary headaches to your program.
Curiosity: although conceptually Enum is not really a class (the constructor cannot be public and it is not you who creates instances of it, for example), it has several characteristics of a regular class, and can have attributes, behaviors and even static members. In fact, looking at the generated bytecode (the compiled java code, so to speak), we can notice that Enums generate the same code as a class after compiled.
– Caffé
@Caffe Yes, it is the same thing as a class, but it changes the right concept. You could publish an answer explaining?
– gato
That, the concept is different: while a class can have all sorts of functions, the function of Enum should be strictly that of representing a fixed list of constant values (of course list and values can change between compilations - but at runtime it is fixed). Given the flexibility of Enum in Java, I’ve seen programmers implement even complex business rules within Enum - this can bring some difficulties as the system grows. My reply is dispensed with given the excellent answer already posted by @utluiz ;-)
– Caffé