Oi! Hoje falaremos sobre um dos tipos de dados especiais de Java:
Enum
(abreviação de "enumeração"). O que o torna especial? Vamos imaginar o que precisamos para implementar "meses" em um programa. Não parece problemático, certo? Só precisamos determinar quais propriedades cada mês possui. Talvez primeiro precisemos do nome do mês e do número de dias nele. A solução parece bem simples:
public class Month {
private String name;
private int daysCount;
public Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDaysCount() {
return daysCount;
}
public void setDaysCount(int daysCount) {
this.daysCount = daysCount;
}
@Override
public String toString() {
return "Month{" +
"name='" + name + '\'' +
", daysCount=" + daysCount +
'}';
}
}
Todo o shabang! Temos uma Month
classe, os campos obrigatórios, getter/setters e toString()
. A menos, é claro, que precisemos adicionar equals()
ehashCode()
para alcançar a felicidade completa :) Mas aqui temos um problema conceitual. Como você provavelmente se lembra, uma das principais vantagens da OOP é que ela facilita a modelagem de entidades do mundo real. Uma cadeira, um carro, um planeta - todos esses conceitos da vida cotidiana são facilmente representados em um programa com a ajuda da abstração. O problema é que algumas entidades do mundo real têm uma faixa de valores estritamente limitada. Há apenas 4 estações em um ano. Existem apenas 8 notas em uma oitava. O calendário tem apenas 12 meses. E Danny Ocean of Ocean's 11 tem apenas 11 amigos (embora isso não importe :)) O que importa é que uma classe Java comum não é capaz de modelar essas entidades e impor suas limitações naturais. NossoMonth
class tem todos os campos obrigatórios. Mas se outro programador o usar, ninguém poderá impedi-lo de criar objetos completamente insanos:
public class Main {
Month month1 = new Month("lolkek", 322);
Month month2 = new Month("yahoooooooooooo", 12345);
}
Se isso aparecer em nosso código, não será fácil encontrar o culpado! Por um lado, o programador que cria os objetos pode perceber que a Month
classe significa "mês em um ano" e não escrever essas bobagens. Por outro lado, o programador está apenas aproveitando as habilidades fornecidas pelo designer de classe. É possível atribuir nomes e números de dias arbitrários? Isso é exatamente o que temos. O que então devemos fazer nesta situação? Honestamente, antes do lançamento do Java 1.5, os programadores precisavam ser criativos :) Naquela época, eles criavam estruturas como esta:
public class Month {
private String name;
private int daysCount;
private Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
public static Month JANUARY = new Month("January", 31);
public static Month FEBRUARY = new Month("February", 28);
public static Month MARCH = new Month("March", 31);
@Override
public String toString() {
return "Month{" +
"name='" + name + '\'' +
", daysCount=" + daysCount +
'}';
}
}
Aqui reduzimos o número de meses de doze para três para tornar o exemplo mais curto. Tais projetos tornaram possível resolver o problema. A capacidade de criar objetos era limitada a um construtor privado:
private Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
Os programadores que usam a classe não podem simplesmente criar Month
objetos. Eles tiveram que usar os objetos estáticos finais fornecidos pelo desenvolvedor da classe. Por exemplo, assim:
public class Main {
public static void main(String[] args) {
Month january = Month.JANUARY;
System.out.println(january);
}
}
Mas os desenvolvedores Java chamaram a atenção para o problema existente. Claro, é ótimo que os programadores tenham conseguido encontrar uma solução usando as ferramentas disponíveis na linguagem, mas não parece muito fácil! Era necessária uma solução óbvia, mesmo para novatos. E assim Enum
apareceu em Java. Basicamente, Enum
é uma classe Java que fornece um conjunto limitado de valores de objeto. Veja como fica:
public enum Month {
JANUARY,
FEBRUARY,
MARCH
}
Na definição, indicamos que Enum
é uma classe Java, mas isso é realmente verdade? Sim, e podemos até verificar isso. Por exemplo, tente fazer nosso Month
enum herdar alguma outra classe:
public abstract class AbstractMonth {
}
// Error! The extends clause cannot be used with an enum
public enum Month extends AbstractMonth {
JANUARY,
FEBRUARY,
MARCH
}
Por que isso acontece? Quando escrevemos:
public enum Month
o compilador converte esta instrução no seguinte código:
public Class Month extends Enum
Como você já sabe, Java não suporta herança múltipla. Portanto, não podemos herdar AbstractMonth
. Como essa nova construção, Enum
, pode ser usada? E como isso difere da antiga construção com static final
campos? Bem, por exemplo, a construção antiga não nos permitia usar nosso próprio conjunto de valores nas switch
declarações. Imagine que queremos criar um programa que nos lembre dos feriados comemorados a cada mês:
public class HolidayReminder {
public void printHolidays(Month month) {
switch (month) {
// Error!
case JANUARY:
}
}
}
Como você pode ver, o compilador gera um erro aqui. Mas uma vez que enum
apareceu no Java 1.5, tudo ficou muito mais simples:
public enum Month {
JANUARY,
FEBRUARY,
MARCH
}
public class HolidayReminder {
public void printHolidays(Month month) {
switch (month) {
case JANUARY:
System.out.println("New Year's Day is January 1st!");
break;
case FEBRUARY:
System.out.println("Valentine's Day is February 14th!");
break;
case MARCH:
System.out.println("Saint Patrick's Day is March 17th!");
break;
}
}
}
public class Main {
public static void main(String[] args) {
HolidayReminder reminder = new HolidayReminder();
reminder.printHolidays(Month.JANUARY);
}
}
Saída do console:
New Year's Day is January 1st!
Observe que o acesso aos Enum
objetos permaneceu estático, exatamente como era antes do Java 1.5. Não precisamos criar um Month
objeto para acessar os meses. Ao trabalhar com enums, é muito importante não esquecer que Enum
é uma classe completa. Isso significa que, se necessário, você pode definir construtores e métodos nele. Por exemplo, no fragmento de código anterior, simplesmente especificamos os valores: JANUARY, FEVEREIRO, MARÇO. No entanto, podemos expandir nosso Month
enum assim:
public enum Month {
JANUARY("January", 31),
FEBRUARY("February", 28),
MARCH("March", 31),
APRIL("April", 30),
MAY("May", 31),
JUNE("June", 30),
JULY("July", 31),
AUGUST("August", 31),
SEPTEMBER("September", 30),
OCTOBER("October", 31),
NOVEMBER("November", 30),
DECEMBER("December", 31);
private String name;
private int daysCount;
Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
public static Month[] getWinterMonths() {
return new Month[]{DECEMBER, JANUARY, FEBRUARY};
}
public static Month[] getSummerMonths() {
return new Month[]{JUNE, JULY, AUGUST};
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDaysCount() {
return daysCount;
}
public void setDaysCount(int daysCount) {
this.daysCount = daysCount;
}
@Override
public String toString() {
return "Month{" +
"name='" + name + '\'' +
", daysCount=" + daysCount +
'}';
}
}
Aqui fornecemos nossos enum
2 campos (o nome do mês e o número de dias), um construtor que usa esses campos, getter/setters, o toString()
método e 2 métodos estáticos. Como você pode ver, não houve problemas com isso. Novamente, Enum
realmente é uma classe completa:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
System.out.println(Arrays.toString(Month.getSummerMonths()));
}
}
Saída do console:
[Month{name='June', daysCount=30}, Month{name='July', daysCount=31}, Month{name='August', daysCount=31}]
Por fim, gostaria de recomendar um livro Java extremamente útil, chamado "Effective Java" de Joshua Bloch . O autor é um dos criadores do Java, então você pode confiar em seus conselhos sobre como usar as ferramentas da linguagem de maneira correta e competente :) Em relação à nossa lição, recomendo que você preste atenção especial ao capítulo do livro sobre Enum
. Leitura feliz! :)
GO TO FULL VERSION