enum Season {AUTUMN, SUMMER, WINTER, SPRING}
♦ An enum is a «special class» (dubbed an enum type), that represents a group of constants.♦ Enum is short for «enumeration», which means «specific list of constant entities». ♦ Enums are created using the enum keyword (instead of class or interface, and separate the constants with a comma. ♦ The constants should be in uppercase (implied agreement of the Java community) ♦ Enum constants are accessed using the dot syntax: Season season = Season.SPRING;
|
enum Season {AUTUMN, SUMMER, WINTER, SPRING} public class Test1 {
public static void main (String [] args) {
Season season = Season.SPRING;
System.out.println (season);
}
} |
Output | SPRING |
Comments ♦ It is not necessary to write the «seasons» in any logical order. ♦ After compilation of Test1.java, 2 files will be created: Test1.class and Season.class |
♦ An enum can also be inside a class: |
public class Test2 {
enum Size {SMALL, MEDIUM, LARGE} public static void main (String [] args) {
Size size = Size.SMALL;
System.out.println (size);
}
} |
Output | SMALL |
Comments ♦ A new «size» can be attached at any time and at any position of the list. Not necessarily at the end: enum Size {XLARGE, SMALL, MEDIUM, LARGE}
♦ After compilation of Test2.java, 2 files will be created: Test2.class and Test2$Size.class
|
♦ enum has a values() method, which returns an array of all its constants. ♦ This method is useful when you want to loop through all of these constants. |
for (Size size : Size.values())
System.out.println (size);
|
Output |
SMALL MEDIUM LARGE |
An enum
Use enums when you have values that you know aren't going to change, like month names, weekday names, color names, etc. |
♦ Enums are often used in switch statements to check for corresponding values: |
enum Size {SMALL, MEDIUM, LARGE} public class Test4 {
public static void main (String [] args) {
Size size = Size.LARGE;
switch (size) { case SMALL:
System.out.println ("Small size");
break;
case Size.MEDIUM:
System.out.println ("Medium size");
break;
case LARGE:
System.out.println ("laaarge size");
break;
} }
} |
Output | laaarge size |
Comments ♦ In switch statement, the simple names of the constants (SMALL) can be used, alongside with the full ones (Size.SMALL) ♦ But be careful. In the statements if, while and do-while, only the full name (Size.LARGE) is expected if (size == Size.LARGE)
System.out.println ("it's large");
|
Suppose we know the name and the average temperature of 3 greek cities. Let's see how to record these 2 pieces of information for each city. |
enum City {
ATHEN ("Αθήνα", 25),
SALONIK ("Σαλονίκη", 21),
CORFU ("Κέρκυρα", 23); final String greekName;
final int averageTemperature; City (String name, int avgTemp) { // the constructor
greekName = name;
averageTemperature = avgTemp;
}
} |
Comments ♦ The constructor will be executed 3 times, each time for every constant (ATHEN, SALONIK and CORFU). ♦ Each constant will have its own 2 attributes (greekName and averageTemperature). They can be referred with the dot syntax: System.out.println (City.ATHEN.greekName); // Αθήνα
♦ Declare the fields final so they cannot be accidentally changed by you.
|
Let's define the two basic arithmetic operations (addition and subtraction) as an enum type with the names PLUS and MINUS. We can give, for each enum constant, a different behavior in a particular method (eg. evaluate). One way to do this is by using the switch statement: |
enum Operation {
PLUS, MINUS; double evaluate (double x, double y) {
switch (this) {
case PLUS: return x + y;
case MINUS: return x - y;
}
throw new AssertionError ("Unknown operation " + this);
}
}
// ─────────────────────────────────────────
public class Test6 {
public static void main (String [] args) {
double x = 12, y = 3;
for (Operation op : Operation.values())
System.out.println (x + " " + op + " " + y + " = " + op.evaluate (x, y));
}
} |
Output |
12.0 PLUS 3.0 = 15.0 12.0 MINUS 3.0 = 9.0 |
Comments ♦ This works fine, but it will not compile without the throw statement, which is not terribly pretty. Worse, we must remember to add a new case to the switch statement each time we add a new constant to Operation. If we forget, the evaluate method will fail, executing the aforementioned throw statement. ♦ Suppose we add a third operation MULTIPLY, without fixing the switch statement: enum Operation {
♦ The result will be a runtime error!
PLUS, MINUS, MULTIPLY; ... |
Output |
12.0 PLUS 3.0 = 15.0 12.0 MINUS 3.0 = 9.0 Exception on thread "main" java.lang.AssertionError: Unknown operation MULTIPLY |
♦ There is another way to give each enum constant a different behavior for some method, that avoids these problems. We can declare the method abstract in the enum type and override it with a concrete method in each constant. Such methods are known as constant-specific methods. Here is the previous example redone using this technique: |
enum Operation {
PLUS {
double evaluate (double x, double y) {
return x + y;
}
},
MINUS {
double evaluate (double x, double y) {
return x - y;
}
},
MULTIPLY {
double evaluate (double x, double y) {
return x * y;
}
}; abstract double evaluate (double x, double y);
}
// ─────────────────────────────────────────
public class Test7 {
public static void main (String [] args) {
double x = 12, y = 3;
for (Operation op : Operation.values())
System.out.println (x + " " + op + " " + y + " = " + op.evaluate (x, y));
}
} |
Output |
12.0 PLUS 3.0 = 15.0 12.0 MINUS 3.0 = 9.0 12.0 MULTIPLY 3.0 = 36.0 |
Comments ♦ This technique does not allow us to forget to implement the evaluate abstract method for the new constant MULTIPLY. ♦ Constant-specific methods are reasonably sophisticated, and many programmers will never need to use them, but it is nice to know that they are there if you need them. |