Troskyvs
Troskyvs

Reputation: 8057

Could java enum class implements "Comparable" interface?

Seems that enum class already has a final compareTo function, which cannnot be overriden. But my requirement is to customize an enum class like this:

enum Operator {
    Add('+', 1),
    Sub('-', 1),
    Mul('*', 2),
    Div('/', 2);

    private char op;
    private int priority;
    private Operator(char _op, int _priority) {
        op = _op;
        priority = _priority;
    }
}

Then I wish to have it implements Comparable interface to have the ability to compare among Add, Sub, Mul, etc. But seems I cannot use implements Comparable<Operator> as described above, javac gives compilation error:

Redundant superinterface Comparable<Operator> for the type Operator, already defined by Enum<Operator>Java(16777547)

So how to achieve my goal? Thanks.

Upvotes: 0

Views: 762

Answers (3)

Alexander Ivanchenko
Alexander Ivanchenko

Reputation: 29028

Then I wish to have it implements Comparable interface to have the ability to compare among Add, Sub, Mul, etc

You can't change the implementation of Comparable in your enum.

Every enum implicitly implements Comparable because its parent java.lang.Enum has implemented this interface and method compareTo() is marked with final modifier, i.e. you can't override it.

Here is the quote from the Javadoc:

public final int compareTo(E o)

Compares this enum with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object. Enum constants are only comparable to other enum constants of the same enum type. The natural order implemented by this method is the order in which the constants are declared.

You can define a Comparator implemented based on the priority property as public static field.

enum Operator {
    MUL('*', 1),
    DIV('/', 1),
    ADD('+', 2),
    SUB('-', 2);
    
    public static final Comparator<Operator> BY_PRIORITY = 
        Comparator.comparing(Operator::getPriority);
    
    private char op;
    private int priority;
    
    Operator(char op, int priority) {
        this.op = op;
        this.priority = priority;
    }
    
    public char getOp() {
        return op;
    }
    
    public int getPriority() {
        return priority;
    }
}

If you need the order to reflect the standard order of arithmetic operations: Multiplication/Division comes before Addition/Subtraction, then the value of priority of the MUL and DIV needs to be lower than the value of priority of ADD and SUB.

The names of enum-member Add, Sub, etc., as well as names of constructor parameters _op, _priority in your code are not aligned with the Java naming convention.

Upvotes: 0

Omega1001
Omega1001

Reputation: 522

Why compare method is final

As you noted correctly, you cannot override the compare function of the enum class, because it is final.

The method is final, because of the semantics of an enum (Enumerated). It represent a number of values that could be completely substituted with there "ordnial" value. Actually, most applications of enum work with the ordinal value only. The names are just to make it easier to handle them.

Thus, the natural sort order (that is defined by the comparable interface) is to order by Ordinals and not on some field values. Actually, most enums don't have fields at all.

So if you find your self in a spot where you need to order enums based on something other than there ordinals, you should probably reconsider using enums ...

What you could do:

I'm going out an a limb here, since you didn't exactly specify what your final goal here is, but in most cases someone tries to implement Comparable, they try to sort a List or Array.

If that is the case, you could just work around that issue using a Comparator. Both the Array.sort, Collections.sort and Stream.sorted method have a overload that accepts a Comperator to define the sort order.

So what you could do is add a method to your enum like

 public static int comparePrio(Operator first, Operator second) {
        return Integer.compare(first.priority, second.priority);
    }

and then call the sort method like this:

Collections.sort(myListOfValues, Operator::comparePrio);

(Code for Arrays and Streams is analog)

Warning: The code is not null save. If null is a possibility, you need to add additional null checks in your comparePrio method

Upvotes: 0

Arsegg
Arsegg

Reputation: 126

You can always declare Comparator.comparingInt(Operator::getPriority) and use it to compare your operators.

Upvotes: 0

Related Questions