Search code examples
javalinked-listcomparablecomparetounchecked

warning: [unchecked] unchecked call to compareTo(T) as a member of the raw type Comparable


I'm recently returning to Java after 10 years and I'm pretty rusty. I'm trying to run some basic sorted list code I had. This code used to compile and run but now I'm getting the following warning:

.\LinkedList.java:30: warning: [unchecked] unchecked call to compareTo(T) as a member of the raw type Comparable
                    return _data.compareTo( ((Node)n)._data );
                                          ^
where T is a type-variable:
T extends Object declared in interface Comparable

This is the code throwing the warning:

static protected class Node implements Comparable
{
    public Node _next;
    public Comparable _data;
    
    protected Node(Comparable data, Node next)
    {
        _next = next;
        _data = data;
    }
    
    public int compareTo(Object n)
    {
        return _data.compareTo( ((Node)n)._data );
    }
    
    public String toString()
    {
        return _data.toString();
    }
    
} // end Node class

My understanding is I can no longer use compareTo() on a raw type, but I'm not sure how to go about fixing it. Any help welcome. Also new to stack overflow so forgive me if I've done this wrong or missed where this has already been answered.


Solution

  • There are two (three) different types of ordering:

    1. A natural order behavior that is implemented by the Class itself
    2. A task-specific order behavior implemented in code
    3. A mix of both, because they're compatible.

    Generally:

    Comparable is a Generic Class, so you should actually use Comparable<T> (T being a class-type), in your example use it reflexively as Comparable<Node> so the compiler knows you have a comparable Node that you want to compare to another (comparable) Node.

    Ordering Type 1: Comparable<T> is used when you have an natural ordering on an element, and the elements incidates its own ordering behaviour.

    Your Code redone:

    1: Nodes that can be compare to Ts, which usually is problematic:

    public class Node<T extends Comparable<T>> implements Comparable<T> {
        public Node<T>  _next;
        public T        _data;
    
        protected Node(final T data, final Node<T> next) {
            _next = next;
            _data = data;
        }
    
        @Override public String toString() {
            return _data.toString();
        }
    
        @Override public int compareTo(final T pO) {
            return _data.compareTo(pO);
        }
    
    } // end Node class
    

    2: Node that can be compared to other nodes, and the T it is containing must be Comparable also:

    This is the default implementation you would use in your case.

    public class Node<T extends Comparable<T>> implements Comparable<Node<T>> {
        public Node<T>  _next;
        public T        _data;
    
        protected Node(final T data, final Node<T> next) {
            _next = next;
            _data = data;
        }
    
        @Override public String toString() {
            return _data.toString();
        }
    
        @Override public int compareTo(final Node<T> pO) {
            return _data.compareTo(pO._data);
        }
    
    } // end Node class
    

    Ordering Type 2: Using a task-specific ordering:

    This is in contrast to the situation above. Here, it's not the element that dictates ordering, but the task at hand:

    The code for the Class does not necessarily need to (but still can) specify an ordering implementation. But then the ordering is done on specific contents with a specific ordering Comparator:

    import java.util.ArrayList;
    import java.util.Collections;
    
    public class MyClass {
    
        public final int    mAge;
        public final String mName;
        public final float  mValue;
    
        protected MyClass(final int pAge, final String pName, final float pValue) {
            mAge = pAge;
            mName = pName;
            mValue = pValue;
        }
    
        @Override public String toString() {
            return "MyClass [mAge=" + mAge + ", mName=" + mName + ", mValue=" + mValue + "]";
        }
    
    
    
        public static void main(final String[] args) {
            final ArrayList<MyClass> list = new ArrayList<>();
            list.add(new MyClass(12, "Chris", 13.7f));
            list.add(new MyClass(14, "Anna", 18.7f));
            list.add(new MyClass(33, "Bob", 3.7f));
    
    
            printList("Unordered", list);
    
            // sort by age
            Collections.sort(list, (p, q) -> p.mAge - q.mAge);
            printList("Sorted by age", list);
    
            // sort by Name
            Collections.sort(list, (p, q) -> p.mName.compareTo(q.mName));
            printList("Sorted by name", list);
    
            // sort by Value
            Collections.sort(list, (p, q) -> (int) Math.signum(p.mValue - q.mValue));
            printList("Sorted by value", list);
        }
    
        private static void printList(final String pMessage, final ArrayList<MyClass> pList) {
            System.out.println(pMessage);
            for (final MyClass item : pList) {
                System.out.println(item);
            }
            System.out.println();
        }
    
    } 
    

    ... and of course Type 3, where you mix both, i.e. have an implements Comparable<> somewhere in the mix and using that