kristofer revised this gist . Go to revision
1 file changed, 372 insertions
javaenums.md(file created)
@@ -0,0 +1,372 @@ | |||
1 | + | # Java Enums: From Basics to Advanced Techniques | |
2 | + | ||
3 | + | Java enumerations (enums) are special data types that allow a variable to be a set of predefined constants. They provide a powerful way to represent a fixed set of values in a type-safe manner. If you're a beginner Java programmer already familiar with basic concepts, understanding enums will significantly enhance your coding toolkit. | |
4 | + | ||
5 | + | ## What Are Enums? | |
6 | + | ||
7 | + | An enum is a special "class" that represents a group of constants (unchangeable variables, like final variables). Here's a simple example: | |
8 | + | ||
9 | + | ```java | |
10 | + | enum Day { | |
11 | + | MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY | |
12 | + | } | |
13 | + | ``` | |
14 | + | ||
15 | + | In this example, `Day` is an enum with seven constants. By convention, enum constants are written in uppercase letters. | |
16 | + | ||
17 | + | ## Why Use Enums? | |
18 | + | ||
19 | + | Before Java 5 introduced enums, developers typically used static final constants to represent fixed sets of values: | |
20 | + | ||
21 | + | ```java | |
22 | + | public class OldDays { | |
23 | + | public static final int MONDAY = 0; | |
24 | + | public static final int TUESDAY = 1; | |
25 | + | // ... and so on | |
26 | + | } | |
27 | + | ``` | |
28 | + | ||
29 | + | This approach had several drawbacks: | |
30 | + | 1. No type safety: You could assign any integer value, even ones that don't correspond to a day | |
31 | + | 2. No namespace: Constants were scattered across classes | |
32 | + | 3. Printability: Printing the integer `0` is less readable than `MONDAY` | |
33 | + | 4. Refactoring challenges: Adding new constants could break existing code | |
34 | + | ||
35 | + | Enums solve these issues by providing type safety, namespacing, readable string representations, and safer refactoring. | |
36 | + | ||
37 | + | ## Basic Usage of Enums | |
38 | + | ||
39 | + | ### Declaring and Using Enums | |
40 | + | ||
41 | + | Enums can be declared inside or outside a class. Here's a simple example: | |
42 | + | ||
43 | + | ```java | |
44 | + | public class WeekdayExample { | |
45 | + | // Enum declared inside a class | |
46 | + | enum Weekday { | |
47 | + | MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY | |
48 | + | } | |
49 | + | ||
50 | + | public static void main(String[] args) { | |
51 | + | Weekday today = Weekday.WEDNESDAY; | |
52 | + | System.out.println("Today is: " + today); | |
53 | + | ||
54 | + | // Using enums in switch statements | |
55 | + | switch (today) { | |
56 | + | case MONDAY: | |
57 | + | System.out.println("Start of the work week"); | |
58 | + | break; | |
59 | + | case FRIDAY: | |
60 | + | System.out.println("End of the work week"); | |
61 | + | break; | |
62 | + | default: | |
63 | + | System.out.println("Middle of the work week"); | |
64 | + | break; | |
65 | + | } | |
66 | + | } | |
67 | + | } | |
68 | + | ``` | |
69 | + | ||
70 | + | ### Real-World Example: Status Codes | |
71 | + | ||
72 | + | Let's see a practical example using enums to represent HTTP status codes: | |
73 | + | ||
74 | + | ```java | |
75 | + | public class HttpRequestExample { | |
76 | + | enum StatusCode { | |
77 | + | OK(200), CREATED(201), BAD_REQUEST(400), NOT_FOUND(404), SERVER_ERROR(500); | |
78 | + | ||
79 | + | private final int code; | |
80 | + | ||
81 | + | StatusCode(int code) { | |
82 | + | this.code = code; | |
83 | + | } | |
84 | + | ||
85 | + | public int getCode() { | |
86 | + | return code; | |
87 | + | } | |
88 | + | } | |
89 | + | ||
90 | + | public static void main(String[] args) { | |
91 | + | StatusCode response = StatusCode.OK; | |
92 | + | System.out.println("Status: " + response + " (" + response.getCode() + ")"); | |
93 | + | ||
94 | + | // Process the response | |
95 | + | processResponse(response); | |
96 | + | } | |
97 | + | ||
98 | + | public static void processResponse(StatusCode status) { | |
99 | + | if (status.getCode() >= 400) { | |
100 | + | System.out.println("Error occurred: " + status); | |
101 | + | } else { | |
102 | + | System.out.println("Request successful: " + status); | |
103 | + | } | |
104 | + | } | |
105 | + | } | |
106 | + | ``` | |
107 | + | ||
108 | + | ## Built-in Enum Methods | |
109 | + | ||
110 | + | Java provides several useful methods for all enum types: | |
111 | + | ||
112 | + | ### values() and valueOf() | |
113 | + | ||
114 | + | ```java | |
115 | + | public class EnumMethodsExample { | |
116 | + | enum Season { | |
117 | + | WINTER, SPRING, SUMMER, FALL | |
118 | + | } | |
119 | + | ||
120 | + | public static void main(String[] args) { | |
121 | + | // values() returns an array of all enum constants | |
122 | + | Season[] allSeasons = Season.values(); | |
123 | + | System.out.println("All seasons:"); | |
124 | + | for (Season season : allSeasons) { | |
125 | + | System.out.println(season); | |
126 | + | } | |
127 | + | ||
128 | + | // valueOf() returns the enum constant with the specified name | |
129 | + | Season winter = Season.valueOf("WINTER"); | |
130 | + | System.out.println("Converted string to enum: " + winter); | |
131 | + | ||
132 | + | // This would throw IllegalArgumentException: | |
133 | + | // Season invalid = Season.valueOf("MONSOON"); | |
134 | + | } | |
135 | + | } | |
136 | + | ``` | |
137 | + | ||
138 | + | ### ordinal() and name() | |
139 | + | ||
140 | + | ```java | |
141 | + | enum Planet { | |
142 | + | MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE | |
143 | + | } | |
144 | + | ||
145 | + | public class EnumOrdinalExample { | |
146 | + | public static void main(String[] args) { | |
147 | + | Planet earth = Planet.EARTH; | |
148 | + | ||
149 | + | // ordinal() returns the position (0-based index) | |
150 | + | System.out.println("Earth's position: " + earth.ordinal()); | |
151 | + | ||
152 | + | // name() returns the exact name of the constant | |
153 | + | System.out.println("Name as declared: " + earth.name()); | |
154 | + | ||
155 | + | // toString() is often overridden, but by default returns the same as name() | |
156 | + | System.out.println("String representation: " + earth.toString()); | |
157 | + | } | |
158 | + | } | |
159 | + | ``` | |
160 | + | ||
161 | + | ## Advanced Enum Features | |
162 | + | ||
163 | + | ### Enums with Fields, Constructors, and Methods | |
164 | + | ||
165 | + | Enums can have fields, constructors, and methods, making them quite powerful: | |
166 | + | ||
167 | + | ```java | |
168 | + | enum CoffeeSize { | |
169 | + | SMALL(8), MEDIUM(12), LARGE(16), EXTRA_LARGE(20); | |
170 | + | ||
171 | + | private final int ounces; | |
172 | + | ||
173 | + | // Constructor must be private or package-private | |
174 | + | CoffeeSize(int ounces) { | |
175 | + | this.ounces = ounces; | |
176 | + | } | |
177 | + | ||
178 | + | public int getOunces() { | |
179 | + | return ounces; | |
180 | + | } | |
181 | + | ||
182 | + | public String getDescription() { | |
183 | + | return name().toLowerCase().replace('_', ' ') + " (" + ounces + " oz)"; | |
184 | + | } | |
185 | + | } | |
186 | + | ||
187 | + | public class CoffeeShopExample { | |
188 | + | public static void main(String[] args) { | |
189 | + | CoffeeSize mySize = CoffeeSize.LARGE; | |
190 | + | System.out.println("I ordered: " + mySize.getDescription()); | |
191 | + | System.out.println("That's " + mySize.getOunces() + " ounces of coffee!"); | |
192 | + | } | |
193 | + | } | |
194 | + | ``` | |
195 | + | ||
196 | + | ### Implementing Interfaces | |
197 | + | ||
198 | + | Enums can implement interfaces, adding even more flexibility: | |
199 | + | ||
200 | + | ```java | |
201 | + | interface Describable { | |
202 | + | String getDescription(); | |
203 | + | double getCost(); | |
204 | + | } | |
205 | + | ||
206 | + | enum PizzaSize implements Describable { | |
207 | + | SMALL(10, 8.99), | |
208 | + | MEDIUM(12, 11.99), | |
209 | + | LARGE(14, 13.99), | |
210 | + | EXTRA_LARGE(16, 15.99); | |
211 | + | ||
212 | + | private final int inches; | |
213 | + | private final double price; | |
214 | + | ||
215 | + | PizzaSize(int inches, double price) { | |
216 | + | this.inches = inches; | |
217 | + | this.price = price; | |
218 | + | } | |
219 | + | ||
220 | + | public int getInches() { | |
221 | + | return inches; | |
222 | + | } | |
223 | + | ||
224 | + | @Override | |
225 | + | public String getDescription() { | |
226 | + | return name() + " (" + inches + " inches)"; | |
227 | + | } | |
228 | + | ||
229 | + | @Override | |
230 | + | public double getCost() { | |
231 | + | return price; | |
232 | + | } | |
233 | + | } | |
234 | + | ||
235 | + | public class PizzaOrderExample { | |
236 | + | public static void main(String[] args) { | |
237 | + | PizzaSize size = PizzaSize.LARGE; | |
238 | + | System.out.println("Pizza size: " + size.getDescription()); | |
239 | + | System.out.println("Cost: $" + size.getCost()); | |
240 | + | } | |
241 | + | } | |
242 | + | ``` | |
243 | + | ||
244 | + | ### Enums with Abstract Methods | |
245 | + | ||
246 | + | You can define abstract methods that each enum constant must implement: | |
247 | + | ||
248 | + | ```java | |
249 | + | enum Operation { | |
250 | + | ADD { | |
251 | + | public double apply(double x, double y) { return x + y; } | |
252 | + | }, | |
253 | + | SUBTRACT { | |
254 | + | public double apply(double x, double y) { return x - y; } | |
255 | + | }, | |
256 | + | MULTIPLY { | |
257 | + | public double apply(double x, double y) { return x * y; } | |
258 | + | }, | |
259 | + | DIVIDE { | |
260 | + | public double apply(double x, double y) { | |
261 | + | if (y == 0) throw new ArithmeticException("Division by zero"); | |
262 | + | return x / y; | |
263 | + | } | |
264 | + | }; | |
265 | + | ||
266 | + | public abstract double apply(double x, double y); | |
267 | + | } | |
268 | + | ||
269 | + | public class CalculatorExample { | |
270 | + | public static void main(String[] args) { | |
271 | + | double x = 10; | |
272 | + | double y = 5; | |
273 | + | ||
274 | + | for (Operation op : Operation.values()) { | |
275 | + | System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y)); | |
276 | + | } | |
277 | + | } | |
278 | + | } | |
279 | + | ``` | |
280 | + | ||
281 | + | ### EnumSet and EnumMap | |
282 | + | ||
283 | + | Java provides special collection implementations for enums that are both efficient and type-safe: | |
284 | + | ||
285 | + | ```java | |
286 | + | import java.util.EnumSet; | |
287 | + | import java.util.EnumMap; | |
288 | + | ||
289 | + | enum DayOfWeek { | |
290 | + | MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY | |
291 | + | } | |
292 | + | ||
293 | + | public class EnumCollectionsExample { | |
294 | + | public static void main(String[] args) { | |
295 | + | // EnumSet example | |
296 | + | EnumSet<DayOfWeek> weekdays = EnumSet.range(DayOfWeek.MONDAY, DayOfWeek.FRIDAY); | |
297 | + | EnumSet<DayOfWeek> weekend = EnumSet.complementOf(weekdays); // SATURDAY and SUNDAY | |
298 | + | ||
299 | + | System.out.println("Weekdays: " + weekdays); | |
300 | + | System.out.println("Weekend: " + weekend); | |
301 | + | ||
302 | + | // EnumMap example | |
303 | + | EnumMap<DayOfWeek, String> activities = new EnumMap<>(DayOfWeek.class); | |
304 | + | activities.put(DayOfWeek.MONDAY, "Start new work tasks"); | |
305 | + | activities.put(DayOfWeek.WEDNESDAY, "Team meeting"); | |
306 | + | activities.put(DayOfWeek.FRIDAY, "Submit weekly report"); | |
307 | + | activities.put(DayOfWeek.SATURDAY, "Hiking"); | |
308 | + | ||
309 | + | for (DayOfWeek day : DayOfWeek.values()) { | |
310 | + | String activity = activities.getOrDefault(day, "No specific plans"); | |
311 | + | System.out.println(day + ": " + activity); | |
312 | + | } | |
313 | + | } | |
314 | + | } | |
315 | + | ``` | |
316 | + | ||
317 | + | ## Singleton Pattern Using Enum | |
318 | + | ||
319 | + | One of the most elegant applications of enums is implementing the singleton pattern: | |
320 | + | ||
321 | + | ```java | |
322 | + | public enum DatabaseConnection { | |
323 | + | INSTANCE; | |
324 | + | ||
325 | + | private final String url = "jdbc:mysql://localhost:3306/mydb"; | |
326 | + | private final String username = "user"; | |
327 | + | private final String password = "pass"; | |
328 | + | ||
329 | + | DatabaseConnection() { | |
330 | + | // Expensive initialization that happens only once | |
331 | + | System.out.println("Database connection initialized"); | |
332 | + | } | |
333 | + | ||
334 | + | public void connect() { | |
335 | + | System.out.println("Connected to " + url); | |
336 | + | } | |
337 | + | ||
338 | + | public void executeQuery(String sql) { | |
339 | + | System.out.println("Executing: " + sql); | |
340 | + | } | |
341 | + | } | |
342 | + | ||
343 | + | public class SingletonExample { | |
344 | + | public static void main(String[] args) { | |
345 | + | // Get the singleton instance | |
346 | + | DatabaseConnection db = DatabaseConnection.INSTANCE; | |
347 | + | ||
348 | + | // Use it | |
349 | + | db.connect(); | |
350 | + | db.executeQuery("SELECT * FROM users"); | |
351 | + | ||
352 | + | // This will reference the same instance | |
353 | + | DatabaseConnection anotherReference = DatabaseConnection.INSTANCE; | |
354 | + | System.out.println("Same instance? " + (db == anotherReference)); | |
355 | + | } | |
356 | + | } | |
357 | + | ``` | |
358 | + | ||
359 | + | ## Best Practices and Considerations | |
360 | + | ||
361 | + | 1. **Use enums for representing fixed sets of constants** | |
362 | + | 2. **Add methods and fields to make enums more useful** | |
363 | + | 3. **Implement interfaces to extend functionality** | |
364 | + | 4. **Consider EnumSet and EnumMap for collections of enums** | |
365 | + | 5. **Be aware that enums can't extend other classes** (they implicitly extend java.lang.Enum) | |
366 | + | 6. **Use enums for the singleton pattern** where appropriate | |
367 | + | ||
368 | + | ## Conclusion | |
369 | + | ||
370 | + | Java enums are much more powerful than simple constant collections. They provide type safety, namespace benefits, and can be extended with fields, methods, and even abstract behavior implementations. By mastering enums, you'll write cleaner, more maintainable, and more robust code. | |
371 | + | ||
372 | + | Whether you're representing days of the week, status codes, or implementing complex behaviors like mathematical operations, enums provide an elegant and type-safe solution that goes well beyond what's possible with simple constants. |
Newer
Older