Java
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented Java
-
Section 4: Collections Framework
-
Section 5: Exception Handling
-
Section 6: Generics
-
Section 7: Functional Java
-
Section 8: Concurrency
-
Section 9: I/O and NIO
-
Section 10: JVM Internals
-
Section 11: Modern Java Features
-
Section 12: Build Tools and Project Structure
-
Section 13: Testing
-
Section 14: Databases and Persistence
-
Section 15: Networking
-
Section 16: Design and Best Practices
-
Section 17: Reflection and Annotations
-
Section 18: Logging and Diagnostics
-
Section 19: Date, Time, and Internationalization
-
Section 20: Java Platform Module System
-
Section 21: Security in Java
-
Section 22: Advanced Collections and Data Structures
-
Section 23: More Concurrency Patterns
-
Section 24: Compression, Files, and System Integration
-
Section 25: GUI Programming
-
Section 26: Practical Projects
-
Section 27: Data Structures and Algorithms
-
Section 28: Interview and Algorithm Practice
-
Section 29: JSON and Data Interchange
-
Section 30: More Concurrency Utilities
-
Section 31: More Collections and Streams Practice
-
Section 32: More File and System Programming
-
Section 33: Standard Library Deep Dive
-
Section 34: More Practice and Drills
-
Section 35: More Testing and Quality
-
Section 36: More Design Patterns and Architecture
-
Section 37: Career and Ecosystem
-
Section 38: More OOP and Architecture Practice
-
Section 39: More Enterprise Concepts
-
Section 40: Advanced JavaFX
-
Section 41: More Interview Practice
36: Enum Methods and Constructors
A lot of people treat Enums as if they're just a more readable version of public static final int. I've seen countless developers use them purely as a list of names—like a menu—without realizing that in Java, an Enum is actually a specialized class. The most common misconception I encounter is the belief that Enums cannot hold state or have constructors because "you can't instantiate a constant."
If you think an Enum is just a label, you're missing out on the most powerful part of the feature. Let's look at why that "constants-only" mindset is wrong. Imagine you're building a system to handle shipping speeds.
// The "Limited" way - just labels
public enum ShippingSpeed {
STANDARD, EXPRESS, OVERNIGHT
}
// To actually use these, you'd end up writing clunky switch statements everywhere:
public double getCost(ShippingSpeed speed) {
switch(speed) {
case STANDARD: return 5.0;
case EXPRESS: return 15.0;
case OVERNIGHT: return 30.0;
default: throw new IllegalArgumentException();
}
}
This works, but it's brittle. Every time you add a new shipping speed, you have to hunt down every switch statement in your codebase to update the costs. It's a maintenance nightmare.
From Simple Labels to Stateful Objects
The correction is simple: give the Enum the data it needs. Because Enums are classes, they can have fields, and those fields can be initialized via a constructor. The trick is that the Enum constructor is called internally by the JVM when the constants are created. You don't call new ShippingSpeed()—in fact, you can't—but the JVM does it for you.
public enum ShippingSpeed {
// These are actually calls to the constructor below!
STANDARD(5.0, 5),
EXPRESS(15.0, 2),
OVERNIGHT(30.0, 1);
private final double price;
private final int daysToDeliver;
// The constructor MUST be private (or package-private).
// Java won't even let you make it public.
ShippingSpeed(double price, int daysToDeliver) {
this.price = price;
this.daysToDeliver = daysToDeliver;
}
public double getPrice() {
return price;
}
public int getDaysToDeliver() {
return daysToDeliver;
}
}
Now, that clunky switch statement from earlier disappears. Instead of asking a helper method what the cost of STANDARD is, you just ask the object itself: ShippingSpeed.STANDARD.getPrice(). I always recommend this approach because it keeps the data and the logic in one place.
Adding Behavior with Enum Methods
Beyond just storing data, you can add actual logic to your Enums. You can write methods that perform calculations based on the internal state of the constant. This transforms your Enum from a data container into a behavioral object.
Let's say we want to calculate the total cost including a luxury tax for faster shipping. We can add a method directly into the Enum:
public enum ShippingSpeed {
STANDARD(5.0, 5),
EXPRESS(15.0, 2),
OVERNIGHT(30.0, 1);
private final double price;
private final int daysToDeliver;
ShippingSpeed(double price, int daysToDeliver) {
this.price = price;
this.daysToDeliver = daysToDeliver;
}
public double calculateTotalWithTax(double taxRate) {
// Only apply tax to speeds faster than STANDARD
if (this == STANDARD) {
return price;
}
return price * (1 + taxRate);
}
}
Note how I used this == STANDARD. Inside an Enum method, this refers to the specific constant being operated on. It's a clean, object-oriented way to handle variation without sprawling if-else blocks across your service layer.
📋 Practical Task
Implementing a Game Difficulty XP Modifier
You are building a combat system for an RPG. Different difficulty levels should provide different amounts of Experience Points (XP) to the player. Instead of using a series of if statements in your Player class, you will implement a DifficultyLevel Enum to handle the logic.
Requirements:
- Create an Enum named
DifficultyLevel. - Add three constants:
EASY,NORMAL, andHARD. - Add a private final field
double xpMultiplier. - Implement a constructor that assigns the multiplier:
- EASY: 0.5x
- NORMAL: 1.0x
- HARD: 1.5x
- Add a method called
calculateXp(int baseXp)that returns thebaseXpmultiplied by thexpMultiplier(cast the result to anint).
Testing your code: In your main method, verify that DifficultyLevel.HARD.calculateXp(100) returns 150.
There are no comments for now.