SwadhyAI Notes

All Java notes

Java Enums

›Short versionOpen if you only have a minute.
  • An enum is a class. Its constants are the only instances, created for you and exposed as public static final fields.
  • You cannot call new on an enum. The constructor is private. You cannot extend the enum with another class.
  • == compares enum constants correctly, because each name is one object. equals agrees with ==.
  • values() lists the constants in declaration order. valueOf("NAME") looks up that exact name and throws if it is unknown.
  • ordinal() is the source position. It changes when you reorder constants. Store a name or an explicit code, not the ordinal.
  • A constant can carry fields and can override a method. The set stays closed: callers handle these instances and no others.

A season is one of four things. A string field will also accept "Wintr", an empty value, and whatever the next caller invents. An is a class whose instances were all created already. is one of those instances, and there will not be a fifth.

A fixed set of objects

Season.java
public enum Season {
    WINTER,
    SPRING,
    SUMMER,
    AUTUMN
}

That declaration is a class extending java.lang.Enum. Each constant is a public static final field holding the one instance of that name. new Season() is illegal. The constructor exists, and the compiler makes it private so only the constant declarations can run it.

java
Season here = Season.WINTER;
Season also = Season.valueOf("WINTER");

System.out.println(here == also);          // true
System.out.println(here.equals(also));     // true
for (Season season : Season.values()) {
    System.out.println(season);
}

returns the existing instance, so == and equals say the same thing. You do not write hashCode for a typical enum. Enum already bases equality on identity, which matches the one-instance rule. walks the constants in source order. valueOf("winter") throws, because the name is WINTER.

Fields, behavior, and a code you control

The class can have a constructor, fields, and methods. Constants pass arguments to that constructor. One constant can override a method with its own body, which is a subclass of the enum class created for that instance alone.

java
public enum Season {
    WINTER("WI") {
        @Override
        public boolean snowLikely() {
            return true;
        }
    },
    SPRING("SP"),
    SUMMER("SU"),
    AUTUMN("AU");

    private final String code;

    Season(String code) {
        this.code = code;
    }

    public String code() {
        return code;
    }

    public boolean snowLikely() {
        return false;
    }

    public static Season fromCode(String code) {
        for (Season season : values()) {
            if (season.code.equals(code)) {
                return season;
            }
        }
        throw new IllegalArgumentException(code);
    }
}

WINTER("WI") calls the constructor. The constructor is still private to everyone outside the enum. snowLikely is an ordinary instance method, overridden on one constant, so the call is dynamic dispatch on that instance. The other constants inherit the method that returns false.

would report 0 for winter only while winter stays first. Insert a constant above it and every stored ordinal now means a different season. code() is a value you chose. fromCode can keep accepting "WI" after you rename a Java identifier. name() returns the identifier, which is a reasonable stored form when the identifiers themselves are the contract.

A switch that knows the members

A on the enum lists constants, not arbitrary strings. A switch expression that must produce a value asks you to cover the ones you left out.

java
int quarter(Season season) {
    return switch (season) {
        case WINTER -> 1;
        case SPRING -> 2;
        case SUMMER -> 3;
        case AUTUMN -> 4;
    };
}

Add MONSOON later and this method stops compiling until you decide its quarter. An int or a String would have waited until a user hit the missing branch. The enum cannot be extended by another file, so the set of cases is the set of instances. It can implement an interface if several enums should be passable to one method, and each enum still brings its own closed list.

Terminal
$ javac Season.java
$ java Season

You store season.ordinal() in a database, then insert a new constant at the top of the enum. What does an old row of 0 mean?

It means whatever constant is now first, which is the new one. The row used to mean winter. Ordinal is the declaration index, and it moved. Store "WINTER" or an explicit code such as "WI", and look the instance up when you read the row.