Java Anti-Patterns – Is Enum Order Sensitivity an Antipattern

anti-patternsenumjava

Is it an anti-pattern to depend on a particular order of an enum's instance declarations? For example, consider:

public enum CompassPoint {
    North,
    East,
    South,
    West;
}

These points are in clockwise order. Is there a good reason to not have code rely on this fact? More specifically, is it "OK" to rely on this code:

 CompassPoint from;
 int toRightIndex = (from.ordinal() + 1) % CompassPoint.values();
 CompassPoint toRight = CompassPoint.values()[toRightIndex];

"OK" here is "best practice", including avoiding a time bomb if someone innocently added instances for the quarter points, which may (or may not) break the intention of the meaning of "to right".

If "not OK", is it less "not OK" if such code is restricted to being internal to the enum class?

Best Answer

I'd also say, you mostly answered the question by your own. I wouldn't implement it that way because it is brittle.

When having that code as part of the enum class itself, it is certainly better because the problem is isolated to the implementation detail of the enum. For the problem at hand I think that solution would be 'good enough' and therefore acceptable.

When assuming that the enum will be used frequently and is likely to be extended in the future, I'd make use of the advanced Java enum features like fields and methods:

    public enum CompassDirection {
    NORTH(0),
    EAST(90),
    SOUTH(180),
    WEST(270);

    private final double degreesFromNorth;

    CompassDirection(double degreesFromNorth) {
        this.degreesFromNorth = degreesFromNorth;
    }

    public CompassDirection directionToRight(){
        directionForDegreesFromNorth(degreesFromNorth + 90);
    }

    public CompassDirection directionToLeft(){
        directionForDegreesFromNorth(degreesFromNorth - 90);
    }

    public CompassDirection directionForDegreesFromNorth(double degreesFromNorth){
        double normalizedDegrees = Math.floorMod(degreesFromNorth, 360);
        for(CompassDirection direction : CompassDirection.values()){
            if(direction.degreesFromNorth == normalizedDegrees){
                return direction;
            }
        }

        throw new Exception("No matching direction could be found");
    }
}

Java enums are really powerful and I must say I miss them badly when programming C#.

Related Topic