Model fixed sets of values with enums, write concise immutable data carriers with records, and group helper types using nested classes.
Why: an enum defines a type that can only be one of a named list of values — like days, directions, or statuses. It is safer than using strings or numbers because the compiler rejects anything not in the list.
public enum Status {
ACTIVE, PAUSED, CLOSED
}
Status s = Status.ACTIVE;
if (s == Status.ACTIVE) {
System.out.println("running");
}
// Status.OPEN would not compile — only the three values existWhy: enums pair naturally with switch — each value gets a branch, and the compiler can warn if you forget one. This is a clean way to do different work depending on a status or mode.
Status s = Status.PAUSED;
String message = switch (s) {
case ACTIVE -> "Up and running";
case PAUSED -> "Temporarily stopped";
case CLOSED -> "No longer available";
};
System.out.println(message); // "Temporarily stopped"Why: a record is a short way to declare a class whose job is to hold data. From one line Java generates the fields, constructor, getters, equals(), hashCode(), and a readable toString() — all the boilerplate you would otherwise type by hand. Records are immutable.
public record Point(int x, int y) { }
Point p = new Point(3, 4);
System.out.println(p.x()); // 3 — auto-generated accessor
System.out.println(p); // Point[x=3, y=4] — auto toString
System.out.println(p.equals(new Point(3, 4))); // true — value equalityWhy: records are still classes, so you can add methods and validate inputs. A compact constructor (no parameter list) runs before the fields are set — perfect for guarding against bad data.
public record Temperature(double celsius) {
Temperature { // compact constructor: validate
if (celsius < -273.15)
throw new IllegalArgumentException("below absolute zero");
}
double fahrenheit() { // an ordinary method
return celsius * 9 / 5 + 32;
}
}
System.out.println(new Temperature(25).fahrenheit()); // 77.0Why: a class declared inside another groups closely-related types together. A static nested class is the common kind — it does not need an outer object and is often a small helper used only by the enclosing class.
public class ShoppingCart {
static class Item { // nested helper type
String name;
double price;
Item(String name, double price) {
this.name = name;
this.price = price;
}
}
Item create(String name, double price) {
return new Item(name, price);
}
}