segunda-feira, 5 de março de 2007

Tipo ENUM

A idéia é escrever um pouco sobre tipo enum, algo que estou aprendendo para usar no projeto DispatchJet.

A principal característica do tipo enum é que seus campos são constantes pré-definidas. São utilizados quando é necessário representar uma lista finita de valores conhecidos (pontos cardeais, dias da semana, etc.).

Quando um enum é declarado, automaticamente ele estende a classe java.lang.Enum e, portanto, é possível acessar os métodos da superclasse. Outra característica é que o construtor de um enum deve ter visibilidade restrita ao package, ou seja, não pode ser utilizado o modificador public em sua declaração. Assim, não é possível fazer chamadas externas ao construtor de um enum.

Segue um enum simples que representa dias da semana:

public enum Days {
   MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRYDAY,
   SATURDAY, SUNDAY;

}

Uma opção comum é que cada field de um enum possua um valor. Abaixo há um exemplo de um enum que define a capacidade volumétrica de copos de refrigerante, em uma aplicação de vendas:

public enum CupSize {
   SMALL(300), MEDIUM(500), LARGE(750);
   private int volume;

   CupSize(int volume) {
      this.volume = volume;
   }

   public String getVolume() {
      return volume + "ml";
   }
}

Podemos observar que uma chamada ao método getVolume() de um copo de 300 ml por exemplo, produzirá o resultado: 300 ml

Finalmente, pode ser necessário que um determinado valor no enum (nesse caso, um certo tamanho de copo), precise emitir uma saída diferente para um método. Suponhamos que seja necessário emitir um alerta quando o usuário escolher o copo de 750ml. Nesse caso, é possível fazer um override do método, conforme o código abaixo:

public enum CupSize {
   SMALL(300),
   MEDIUM(500),
   LARGE(750) {

      public String getVolume() {
      return "Atencao: Voce escolheu um copo de " +
         this.volume + " ml!";

      }
   };

   int volume;

   CupSize(int volume) {
      this.volume = volume;
   }

   public String getVolume() {
      return volume + " ml.";
   }
}

O método getVolume() definido nas linhas 5 a 8 faz override do método original, definido entre as linhas 17 e 19. Assim, quando é feita uma chamada à getVolume(), para um copo de 750ml, o método "particular" é acionado, ao invés do método comum a todos os demais enums.

Veja o resultado obtido executando-se o código abaixo:

public class Lanchonete {
   public static void main(String[] args) {
      CupSize copo = CupSize.MEDIUM;
      CupSize grande = CupSize.LARGE;
      System.out.println (copo.getVolume());
      System.out.println (grande.getVolume());
   }
}

Resultado:

500 ml.
Atencao: Voce escolheu um copo de 750 ml!

Uma outra característica interessante dos enums é que o compilador adiciona alguns métodos automaticamente ao compilá-los. Um dos métodos adicionados é o values() que permite fazer iterações sobre o enum com um enhanced for, conforme abaixo:

public static void main(String[] args) {
   for (CupSize c : CupSize.values())
      System.out.println(c.getVolume());
}

A execução do método acima produz o seguinte resultado:

300 ml.
500 ml.
Atencao: Voce escolheu um copo de 750 ml!

Referências:

The Java Tutorial: http://java.sun.com/docs/books/tutorial/java/javaOO/enum.html
Java API: http://java.sun.com/javase/6/docs/api/

Até a próxima.







Um comentário:

Cristina Belderrain disse...

Mesmo contando com tantas opções, é melhor pensar duas vezes antes de usar um enum como uma classe... O fato de um enum, em Java, se comportar como uma classe, não é exatamente uma vantagem, em minha opinião. Em outras linguagens, um enum é apenas um conjunto de constantes tipadas: por serem tipadas, elas permitem que o compilador verifique se o valor que você está usando está entre aqueles definidos no tipo enum. Assim, um erro que só apareceria em tempo de execução passa a ser detectado em tempo de compilação.

Em outro blog encontrei um artigo sobre uma aplicação real que usa o enum do jeito que ele é normalmente usado em outras linguagens. Nesse exemplo, o enum LicenseType é definido na classe LicenseDialog, assim:

 public class LicenseDialog {
 
     public enum LicenseType { APACHE, BSD, LGPL };
     // [...]
 
 }

Se o código cliente quiser se referir à licença BSD, por exemplo, basta usar LicenseDialog.LicenseType.BSD.

Creio que essa é a verdadeira finalidade do enum... Agora, se o que estamos precisando vai além disso, por que não usar uma classe, simplesmente ;-)?