enum replacing class

Figure 445. enum Day replacing public class Day Slide presentation
public class Day {

  static public final Day
    MONDAY    = new Day("Monday"),
             ...
    SUNDAY    = new Day("Sunday");

  public final String name;

  private Day(final String name) {       
    this.name = name;
  }
    public String toString() { 
      return name; }
}
public enum Day {

  MONDAY("Monday"),
  ...
  SUNDAY("Sunday");

  final String name;

  Day(final String name) {
     this.name = name;
  }
  public String toString() {       
    return name;}
}

Figure 446. switch statements back working again Slide presentation
public enum Day {
...
  public static String getItalianDayName(final Day day) {
    switch (day) {
      case MONDAY:    return "Lunedì";
      case TUESDAY:   return "Martedì";
   ...
      case SUNDAY:    return "Domenica";
    }
    return null; // Actually unreachable, but static compiler code analysis is limited
  }
}

Figure 447. enum constructor being implicitly private Slide presentation
public enum Day {
  ...
  private Day(final String name)
    { ...

Compile time warning:

Modifier 'private' is redundant for enum constructors

public enum Day {
  ...
  public Day(final String name)
    { ...

Compile time error:

Modifier 'public' not allowed here

Prohibits enum external instance creation.


Figure 448. A minimal enum Slide presentation
Code
public enum DoorState {       
    OPEN,
    CLOSED,
    LOCKED;
}
DoorState state; 
    ...
IO.println("State: " + state); // toString() exists!       
switch (state) {
  case LOCKED -> IO.println("Stay out!");
  case OPEN -> IO.println("Just enter");
  case CLOSED -> IO.println("Use handle to open");
}
Result
State: CLOSED
Use handle to open

Figure 449. An enum's parent class Slide presentation
Code
IO.println(DoorState.class.getSuperclass());
Result
class java.lang.Enum

See Enum for details.


Figure 450. Iterate over all enum values Slide presentation
Code
for (final Day d: Day.values()) {
  IO.println(d + ", ordinal value: " + d.ordinal());
}
Result
Monday, ordinal value: 0
Tuesday, ordinal value: 1
Wednesday, ordinal value: 2
Thursday, ordinal value: 3
Friday, ordinal value: 4
Saturday, ordinal value: 5
Sunday, ordinal value: 6

Figure 451. Definition order matters! Slide presentation
Code
public enum Day {
    SUNDAY  ("Sunday"),
    SATURDAY("Saturday"),
    FRIDAY("Friday"),
    THURSDAY("Thursday"),
    WEDNESDAY("Wednesday"),
    TUESDAY("Tuesday"),
    MONDAY("Monday");
 ...
}
for (final Day d: Day.values()) {
  IO.println(d + ", ordinal value: " + d.ordinal());      
}
Result
Sunday, ordinal value: 0
Saturday, ordinal value: 1
Friday, ordinal value: 2
Thursday, ordinal value: 3
Wednesday, ordinal value: 4
Tuesday, ordinal value: 5
Monday, ordinal value: 6

Figure 452. Get an enum instance by its ordinal value Slide presentation
Code
final int ordinalOfWednesday = 2; // 0: MONDAY 1:TUESDAY 2:WEDNESDAY ...
final Day d = Day.values()[ordinalOfWednesday];

IO.println(d);
Result
Wednesday

Figure 453. Get an enum instance by its constant's textual name Slide presentation
Code
final DoorState state = DoorState.valueOf("LOCKED");

IO.println(state);
Result
LOCKED

exercise No. 165

Getting a day's predecessor

Q:

Extend enum Day by adding a predecessor() method returning a given day's preceding day:

/**
 * Get the current day's predecessor.
 * 
 * Example Starting from {@link #TUESDAY} we get {@link #MONDAY}
 * 
 * @return The day's predecessor (yesterday)
*/
public Day predecessor() {
    ...
}

Expected execution:

Code
for (final Day d: Day.values()) {
  IO.println(d + ", preceding day is " + d.predecessor());
}
Result
Monday, preceding day is Sunday
Tuesday, preceding day is Monday
Wednesday, preceding day is Tuesday
Thursday, preceding day is Wednesday
Friday, preceding day is Thursday
Saturday, preceding day is Friday
Sunday, preceding day is Saturday

A:

/**
 * Get the current day's predecessor.
 * 
 * Example Starting from {@link #TUESDAY} we get {@link #MONDAY}
 * 
 * @return The day's predecessor (yesterday)
*/
public Day predecessor() {
  final int ordinal = ordinal();
 final int ordinalOfPredecessor = (ordinal + values().length - 1) % values().length;

 return values()[ordinalOfPredecessor];
}

exercise No. 166

Compass directions

Q:

We consider an eight direction compass rose:

Provide an enum Direction to be usable in the following manner:

final Direction northWest = Direction.NW;

IO.println(northWest);
north by west (315°)

Tip

Provide an appropriate constructor among with suitable «internal» instance attributes and a corresponding toString() method.

A:

The desired output contains both a given direction's oral description and a 0 - 360° degree value. We thus start by:

public enum Direction {
  int degree;
  String fullName;
}

For creating a Direction instance a constructor accepting both values is being required:

public enum Direction {

  N(0, "north"); 

  Direction(final int degree, final String fullName) { 
    this.degree = degree;
    this.fullName = fullName;
  }

  public final int degree; 
  public final String fullName;
}

For the sake of simplicity we only create the «north» direction here.

Constructor accepting:

  1. A degree value e.g. 90° representing «eastern» direction.

  2. An informal name e.g. «east».

Two public attributes representing both a direction's degree value and its informal name.

For creating output texts like e.g. north by west (315°) we need a toString() method. Also adding the yet missing directions our final result looks like:

public enum Direction {

  N(   0, "north"),
  NE( 45, "north by east"),
  E(  90, "east"),
  SE(135, "south by east"),
  S( 180, "south"),
  SW(225, "south by west"),
  W( 270, "west"),
  NW(315, "north by west");

  Direction(final int degree, final String fullName) {
    this.degree = degree;
    this.fullName = fullName;
  }

  @Override
  public String toString() {
    return fullName + " (" + degree + "°)";
  }

  public final int degree;
  public final String fullName;
}

exercise No. 167

Compass direction neighbours

Q:

We would like to «invert» a given direction e.g. turning N to S and vice versa. Extend Compass direction neighbours by adding an opposite() method to be used like:

final Direction southWest = Direction.SW;

IO.println("Direction: " + southWest);
IO.println(" Opposite: " + southWest.opposite());
Direction: south by west (225°)
 Opposite: north by east (45°)

Tip

  • Consider the method public static T[] values() being added by the compiler implicitly to any enum class. See the method 's valueOf() explanation. It allows you to access the array of all instances of a given enum.

  • The ordinal() method returns a given enum's instance index with respect to the order of appearance. Using the above values() method you can thus access any index by its value. Use this to calculate the opposite compass direction's index value.

A:

Using a switch allows for a straightforward and simple solution:

public enum Direction {
  ...
  public Direction opposite() {
    return switch (this) {
      case N  -> S;
      case NE -> SW;
      case E  -> W;
      case SE -> NW;
      case S  -> N;
      case SW -> NE;
      case W  -> E;
      case NW -> SE;
    };
  }
  ...
}

Following the provided hint we may instead calculate the opposing direction:

public Direction opposite() {
  return values()[ (ordinal() + 4) % 8];
}

exercise No. 168

Former zodiac examination task

Q:

Implement the zodiac task 2 from the 2024 winter examination implementation project.