MA-JAVA0 · Module 9
enum types
Topics: enum · Constants · switch with enum · Fields on enum constants
Overview
Session 9 — enum types
Some values are best thought of as a small fixed set of named choices: a day of the week, a suit of cards, a shipping status, a direction. Java models these with an enum — a type whose constants are spelled out once and checked by the compiler.
This session shows how to declare an enum, use its constants with switch and if, attach fields and methods to them, and recognise when an enum is the right tool instead of loose string or integer codes.
Time: about 75 minutes.
Concepts
1. The problem enums solve
Before enums, programmers often encoded choices as magic numbers or loose strings: 1 for pending, 2 for shipped, 3 for delivered. That approach has two failure modes:
- Nothing stops a caller from writing
status = 99;— a value nobody meant. "Shipped"versus"shipped"versus"SHIPPED"are three different strings, and a typo silently behaves like a brand-new category.
An enum makes the legal choices part of the type itself. You enumerate them once, and the compiler refuses any value that is not on the list.
public enum Status {
PENDING,
SHIPPED,
DELIVERED
}
Every name inside the braces becomes a constant of type Status. You refer to them as Status.PENDING, Status.SHIPPED, Status.DELIVERED.
2. Declaring and using an enum
An enum is its own file (like a class), named with UpperCamelCase — Status, DayOfWeek, Suit. The constant names follow the same convention as static constants: ALL_CAPS.
Using the values is deliberately simple:
Status current = Status.PENDING;
if (current == Status.PENDING) {
System.out.println("Not shipped yet.");
}
Because the constants are the only instances that can ever exist, comparing enum values with == is safe and idiomatic. This is one of the few places where == on a reference is exactly right — there is no risk of two equal-looking but different objects, because the type only has the handful of instances you declared.
You can also iterate over the full set with the implicit values() method:
for (Status s : Status.values()) {
System.out.println(s);
}
// PENDING
// SHIPPED
// DELIVERED
values() returns an array of the constants in declaration order, which is handy for printing menus or building reports.
3. switch with enums
An enum pairs beautifully with switch — the compiler even checks that you covered the interesting cases:
switch (current) {
case PENDING:
System.out.println("Awaiting dispatch");
break;
case SHIPPED:
System.out.println("On the road");
break;
case DELIVERED:
System.out.println("Arrived");
break;
default:
System.out.println("Unknown status");
}
Note the case labels drop the Status. prefix — you write case PENDING, not case Status.PENDING. The compiler knows from the switch expression's type which enum you mean.
4. Enums can carry fields and behaviour
An enum is not just a list of names — it is a class in disguise. Each constant can carry fields (declared after a semicolon), a constructor (called once for each constant), and methods available on all constants.
public enum Size {
SMALL(1, "S"),
MEDIUM(2, "M"),
LARGE(3, "L");
private final int rank;
private final String label;
Size(int rank, String label) {
this.rank = rank;
this.label = label;
}
public int rank() {
return rank;
}
public String label() {
return label;
}
}
Each constant's declaration passes arguments to the constructor: SMALL(1, "S") runs Size(1, "S"), giving that constant rank = 1 and label = "S". You then read the data back through the methods:
Size pick = Size.MEDIUM;
System.out.println(pick.label()); // M
System.out.println(pick.rank()); // 2
This is where enums beat plain strings: the label "M" and the ordering rank 2 travel with the MEDIUM constant, so no separate lookup table or if chain is needed.
5. name(), toString(), and parsing text back
Every enum constant inherits two useful methods:
name()— the constant's declared name as a string ("PENDING").toString()— by default the same asname(), but you may override it in the enum body to return something friendlier, like thelabelfield above.
Going the other direction — from text back to a constant — uses the implicit static valueOf:
Status s = Status.valueOf("SHIPPED"); // the SHIPPED constant
valueOf is case-sensitive and throws IllegalArgumentException for anything that is not a constant name, so pair it with a try/catch or a controlled input range when parsing user input.
6. When to reach for an enum
An enum earns its place when all three hold:
- The set of legal values is small and closed — you can name every one.
- The values carry meaning beyond a raw number (a label, a rank, a rule).
- You compare them for equality or branch on them (switch, equality checks).
If the set is open-ended (user-defined titles, arbitrary tags), an enum is the wrong tool — use a String or a small class instead.
7. Pitfalls worth memorising
- No arbitrary instances.
new Status()does not compile — enums are the constants you declared, period. ==is correct for enums; do not reach for.equalsout of habit (though it works too).- Case-sensitivity in
valueOf."shipped"throws; only"SHIPPED"matches. switchlabels drop the prefix —case PENDING:, notcase Status.PENDING:.- Enums and mutable state. Fields on an enum are shared by the whole program (there is exactly one
SHIPPED), so keep enum fields effectively final — rarely mutate them at runtime.
Examples
Example A — a weekday enum with a weekend helper
public enum Weekday {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY;
public boolean isWeekend() {
return this == SATURDAY || this == SUNDAY;
}
}
Because each Weekday constant is unique, comparing with == is exact — there is exactly one SATURDAY in the entire program. A caller can then ask a day about itself:
Weekday today = Weekday.FRIDAY;
System.out.println(today.isWeekend()); // false
System.out.println(Weekday.SUNDAY.isWeekend()); // true
Example B — switch over a direction
public enum Direction {
NORTH, EAST, SOUTH, WEST
}
public class Navigator {
public static String describe(Direction d) {
switch (d) {
case NORTH: return "heading up";
case SOUTH: return "heading down";
case EAST: return "heading right";
case WEST: return "heading left";
default: return "lost";
}
}
public static void main(String[] args) {
System.out.println(describe(Direction.EAST)); // heading right
System.out.println(describe(Direction.NORTH)); // heading up
}
}
The case labels use the bare constant names — case NORTH: — because the compiler infers the enum type from d. Every branch returns, so no break is required here.
Example C — enum with fields for a product size
public enum Size {
SMALL(1, "S"),
MEDIUM(2, "M"),
LARGE(3, "L");
private final int rank;
private final String label;
Size(int rank, String label) {
this.rank = rank;
this.label = label;
}
public int rank() {
return rank;
}
public String label() {
return label;
}
}
Driving a little order summary:
public class Order {
public static void main(String[] args) {
Size item = Size.LARGE;
System.out.println("You picked " + item.label() + " (rank " + item.rank() + ")");
for (Size s : Size.values()) {
System.out.println(s.name() + " -> " + s.label());
}
}
}
values() iterates the constants in declaration order, so the output lists SMALL, MEDIUM, LARGE — and each one reports the label you attached in its declaration.
Example D — parsing text into an enum safely
public class ParseStatus {
public static Status parse(String raw) {
try {
return Status.valueOf(raw.trim().toUpperCase());
} catch (IllegalArgumentException e) {
return null;
}
}
public static void main(String[] args) {
System.out.println(parse(" shipped ")); // SHIPPED
System.out.println(parse("delivered")); // DELIVERED
System.out.println(parse("bogus")); // null
}
}
Normalising with trim().toUpperCase() makes the parser tolerant of the sloppy input real users produce. Catching IllegalArgumentException turns a crash into a controlled null (or you could rethrow with a friendlier message).
What to look for when reading these
- The constructor runs once per constant —
SMALL(1, "S")wires up that constant's data at enum-load time. ==compares by identity and is safe here because the constants are unique instances.values()+name()give you the whole menu as strings for printing or parsing.
Bridge
Constructors, static members ↔ enum
Enums reuse ideas you already met in Session 8:
-
Enums are classes in miniature. The constructor runs once per constant (
SMALL(1, "S")), exactly likenewruns a constructor once per object — except the "objects" here are the fixed constants you declared. -
Constants are static members. Referencing
Size.LARGEis the sameClassName.MEMBERpattern asVersion.CODEfrom the constructors session — the enum constants live with the type, not with instances you create. -
==works because instances are unique. Session 6 warned that==on arbitrary references compares addresses. Enums are the deliberate exception: the type guarantees only its declared instances exist, so address comparison is meaningful comparison. -
switchreappears. You metswitchon integers in Session 3; now it branches on enum constants, with the samebreakdiscipline. -
PiggyBank and enums both answer "what choices exist?" A class's
privatefields say what state an object can hold; an enum says what categories a value can be. Midterm-style questions may ask you to model a fixed set — that is when an enum, not a string, is the answer.
When constants and constructors feel like the same story, you have internalised classes — and enums stop being a new topic and start being a convenience.
Practice check — enum types
Multiple-choice check from the Matheion app lesson. Pick an answer for each question, then submit.
1.Given `enum Direction { NORTH, EAST, SOUTH, WEST }`, which expression is valid?
2.What does `Status.valueOf("shipped")` do when `Status` has `PENDING, SHIPPED, DELIVERED`?
3.Why is `==` a safe comparison for enum values but not for `String` content?
4.In a `switch` over `Size.MEDIUM`, how do you write the case for the medium constant?
5.`enum Size { SMALL(1, "S"), MEDIUM(2, "M"), LARGE(3, "L"); ... }` — when is `Size(int, String)` called?
6.What does `for (Status s : Status.values())` print for `enum Status { PENDING, SHIPPED, DELIVERED }`?