Why and when to use enum in Java?

Someone who is learning the language, novice or experienced, may never have come across Java enumerations. I have read for several times that they are useful, for example, to implement the singleton patterns with more guarantees of visibility between threads.

What is the use of learning and using enum in day-to-day programming?

 40
Author: bfavaretto, 2014-02-25

1 answers

The enum represent a fixed set of values, in a more or less self-documented Form . They make code more explicit, more readable, and less vulnerable to programming errors.

A common alternative is to use String or int for constant values. The enum have some advantages over these types:

  • The compiler does not allow typographical errors, as can happen with string literals.

  • The compiler it does not allow values that are outside the enumerated set, which is a consequence of enumerations being types themselves.

  • It is not necessary to write preconditions, or manual tests, to ensure that the argument of a method is within the accepted range of values.

  • The type invariant is free, again because the Enumerations are types, and they set the values at the start be.

  • Enumerations can define behavior (methods) for their constants, as in any usual class.

  • Constants in an enumeration can specialize their behavior: each constant can have its own definition of a method.

  • The virtual machine gives guarantees of thread safety when loading the enumeration.

  • They can also be used in switch.

There are still some creative uses of enumerations, such as state machines, as seen in this blog.


Let's look at a practical example of these advantages. Imagine a program that receives two colors and tries to combine them, according to the RGB system.

Using int

public static final int
    VERMELHO    = 1,
    AZUL        = 2,
    VERDE       = 4,
    AMARELO     = 5,
    CIANO       = 6,
    ROXO        = 3,
    BRANCO      = 7;

/**
 * @pre cor1 == VERMELHO || cor1 == AZUL || cor1 == VERDE ||
 *    cor1 == CIANO || cor1 == AMARELO || cor1 == ROXO || cor1 == BRANCO;
 * @pre cor2 == VERMELHO || cor2 == AZUL || cor2 == VERDE ||
 *    cor2 == CIANO || cor2 == AMARELO || cor2 == ROXO || cor2 == BRANCO;
 * @post cor1 == VERMELHO && cor2 == VERDE => return == AMARELO;
 * @post ...
 */
public static int combina(int cor1, int cor2) {
    if (!corValida(cor1)) return -1;
    if (!corValida(cor2)) return -1;
    return cor1 | cor2;
}

private boolean corValida(int cor) {
    return cor == VERMELHO || cor == VERDE || cor == AZUL ||
        cor == AMARELO || cor == CIANO || cor == ROXO || cor == BRANCO;
}

public static void main(String[] args) {
    int cor = combina(1, 2);
    // O que acontece quando VERMELHO e AZUL deixam de ser 1 ou 2?
    assert cor == ROXO;
}

Using enum

/*
 * Os codigos numéricos não fazem qualquer falta.
 * Seria possível resolver com switch, mas ficaria muito extenso para exemplo.
 * Contudo, um caso real deveria retirar os códigos,
 * para maiores garantias de que não há erro humano.
 */
public static enum Cor {
    VERMELHO(1), AZUL(2), VERDE(4), AMARELO(5), CIANO(6), ROXO(3), BRANCO(7);
    private final int codigo;

    Cor(int codigo) { this.codigo = codigo; }

    int codigo() { return codigo; }

    public static Cor porCodigo(int codigo) {
        for (Cor cor: Cor.values()) {
            if (codigo == cor.codigo()) return cor;
        }
        throw new IllegalArgumentException("codigo invalido");
    }
}

/**
 * @pre cor1 != null && cor2 != null;
 * @post cor1 == Cor.VERMELHO && cor2 == Cor.VERDE => return == Cor.AMARELO;
 * @post ...
 */
public static int combina(Cor cor1, Cor cor2) {
    int combinado = cor1.codigo() | cor2.codigo();
    return Cor.porCodigo(combinado);
}

public static void main(String[] args) {
    Cor cor = combina(Cor.VERMELHO, Cor.AZUL);
    assert cor == Cor.ROXO;
}
 45
Author: afsantos, 2014-02-26 12:26:05