When and why we have to implement Comparable interface? - java

in which situations we have to implement the Comparable interface?

When you want to be able to compare 2 objects and get a result of equal, less than, or greater than.
Implementing Comparable gives your objects a compareTo method. If you add them to a sorted list then they will automatically be sorted based on what your compareTo method returns.
It's pretty basic. I don't know what else there is to add.

When your class implement the Comparable interface, you have to implement the compareTo() method in a way that you can clearly tell where an instance of your class would go in an ordered list of such instances.
Implementing efficient sorting algorithms and ordered collections isn't trivial. Therefore you would do this when you want objects of a class to have natural ordering, so you can use the proven sorting and order-dependent algorithms and classes provided by Java instead of implementing your own, like having the contents of a TreeSet remain ordered after insertions/deletions, or using Collections.sort().

Related

Saving our own objects as keys in TreeMap

I was just wondering if there is any consideration to have in account when saving our own objects in a TreeMap. Something similar when we save our own objects as keys in a hashmap that we need to override equals and hashcode method to be able to retrieve them later. In a treemap there is no hash, a black red algorith is used, but I don't know if there is something special to do.
If so, could you tell me if there is something to have in account?
Thanks
The javadoc says:
The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation time
So you need to implement a natural ordering correctly, or implement a Comparator correctly.
It also says:
Note that the ordering maintained by a tree map, like any sorted map, and whether or not an explicit comparator is provided, must be consistent with equals if this sorted map is to correctly implement the Map interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Map interface is defined in terms of the equals operation, but a sorted map performs all key comparisons using its compareTo (or compare) method, so two keys that are deemed equal by this method are, from the standpoint of the sorted map, equal. The behavior of a sorted map is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Map interface.
So, if you want to obey the general contract of Map (and you should, generally), the compareTo() method must be consistent with equals(), which means that you need to correctly implement an equals() method, and transitively, a hashCode() method, and that you must make sure that a.equals(b) iff e.compareTo(b) == 0.
Most of the times, people screw up because they implement a compareTo/compare method that returns 0 for two objects, and still expect these two objects to be considered different by the map.
Apart from equals and compareTo transitivity there's one more thing that's terribly important.
Your keys, or at least the fields you're using for comparison, should be immutable.
And you can actually use anything as a key for a TreeMap as long as you provide custom Comparator in its constructor.

Java Object Ordering for Sorted Collections

When I'm looking at the Java Object Ordering tutorial, the last section 'Comparators' of the article confused me a little bit.
By defining a class Employee which itself is comparable by employee's name, the tutorial doesn't show if this class has overridden the equals method. Then it uses a customized Comparator in which the employees are sorted by the seniority to sort a list of employees and which I could understand.
Then the tutorial explains why this won't work for a sorted collection such as TreeSet (a SortedSet), and the reason is:
it generates an ordering that is not compatible with equals. This means that this Comparator equates objects that the equals method does not. In particular, any two employees who were hired on the same date will compare as equal. When you're sorting a List, this doesn't matter; but when you're using the Comparator to order a sorted collection, it's fatal. If you use this Comparator to insert multiple employees hired on the same date into a TreeSet, only the first one will be added to the set; the second will be seen as a duplicate element and will be ignored.
Now I'm confused, since I know List allows duplicate elements while Set doesn't based on equals method. So I wonder when the tutorial says the ordering generated by the Comparator is not compatible with equals, what does it mean? And it also says 'If you use this Comparator to insert multiple employees hired on the same date into a TreeSet, only the first one will be added to the set; the second will be seen as a duplicate element and will be ignored.' I don't understand how using a Comparator will affect the use of original equals method. I think my question is how the TreeSet will be produced and sorted in this case and when the compare and equals methods are used.
So I wonder when the tutorial says the ordering generated by the Comparator is not compatible with equals, what does it mean?
In this example, the Comparator compares two Employee objects based on their seniority alone. This comparison does not in any way use equals or hashCode. Keeping that in mind, when we pass this Comparator to a TreeSet, the set will consider any result of 0 from the Comparator as equality. Therefore, if any Employees share starting dates, only one will be added because the set thinks they are equal.
Finally:
I think my question is how the TreeSet will be produced and sorted in this case and when the compare and equals methods are used.
For the TreeSet, if a Comparator is given, it uses the compare method to determine equality and ordering of objects. If no Comparator is given, then the set uses the compareTo method of the objects being sorted (they must implement Comparable).
The reason why the Java specification claims that the compare/compareTo method being used must be in line with equals is because the Set specification makes use of equals, even though this specific type of Set, the TreeSet, uses comparisons instead.
If you ever receive a Set from some method implementation, you can expect that there are no duplicates of the objects in that Set as defined by the equals method. Because TreeSet doesn't use this method, however, developers must be careful to ensure that the comparison method results in the same equality as equals does.
A TreeSet uses only the Comparator to determine if two elements are "equal":
https://docs.oracle.com/javase/7/docs/api/java/util/TreeSet.html
Note that the ordering maintained by a set (whether or not an explicit comparator is provided) must be consistent with equals if it is to correctly implement the Set interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Set interface is defined in terms of the equals operation, but a TreeSet instance performs all element comparisons using its compareTo (or compare) method, so two elements that are deemed equal by this method are, from the standpoint of the set, equal. The behavior of a set is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Set interface.
This means that the Comparator should return 0 if and only if the equals returns true, to get a consistent behaviour between TreeSet and other sets, like a HashSet. The HashSet indeed uses equals and the hash code to determine if two elements are "equal".

Collections -ArrayList

I have a arraylist and it contains a 100 employee object and each object contains "Name" and "Salary". We need to find the Max salaried employeee from the Object .Please let me know what is the way .
I thought of implementing compareTo and equals Method is it right , and also using Collections.sort Is it the right way or is there any other way
If the language is Java, then either implement the Comparable interface (just compareTo--no need for equals) for the objects in the array list and call Collections.sort(arraylist), or else write a Comparator and call Collections.sort(arraylist, comparator). The latter is more flexible, as it doesn't require your objects to always be sorted by salary.
You need not do the sorting yourself. Your case is perfect for priority queues. Write a comparator as #Ted suggested and add the data to PriorityQueue - it'll give you the min or max based on the data you want the min/max of - salary in your case. Details in this post:
How do I use a PriorityQueue?

Sorting generics in Java

I have to implement a generic AVL tree as homework. It's defined as follows:
public class AVL<Key,Elem>;
The problem is that I assume that at some point, I'll have to compare keys to decide in which side of a node I allocate an element. For the purpose of this homework, Integers will be used as Keys.
Since no other restriction or information about that is given, I first thought of just asuming that Key will always be an Integer. However, that makes the generic "Key" superfluous, and I don't think that's what the teachers expect. So, I think that the best solution involves forcing that whatever that is passed as Key implements a Comparator, or something like that (I've really never worked with Comparator, just guessing), and then using that comparator to compare the Keys instead of using the ==,<,> and != operators. However, I have no idea on how to do it. Any hints?
Thanks in advance.
Try public class AVL<Key extends Comparable<Key>,Elem>; and use the compareTo() method which is required by the Comparable<T> interface and which is implemented by Integer.
The SortedMap and SortedSet implementations in the standard Java API either use a Comparator<Key> and call its compare(k1, k2) method, or assume the keys implement Comparable<Key>, and call k1.compareTo(k2). Most offer both, depending on which constructor is used. (EnumMap/EnumSet don't, as they support only the build-in ordering of the enum values by declaration order.)
The Comparable approach mandates that the keys are always sorted in the same way, and would be used for keys which have a canonical ordering (like integers), where you want to use this ordering.
The Comparator approach is more flexible, since you can use the same key objects for different maps where they are differently ordered, and you can use it for keys over which you have no control, or who don't have a canonical ordering (like List, trees/graphs, etc. You can also use it to sort strings keys by other criteria than the pure unicode value (e.g. Locale-based), using a Collator (this is a class implementing Comparator).
Both require a total order on your keys, but I suppose this is necessary for your AVL tree, too.
Here is a Comparator implementation which works on any comparable objects, so you could use it (maybe internally) as an adapter for the Comparable variant.
public static <X extends Comparable<X>> Comparator<X> makeComparator() {
return new Comparator<X>() {
public int compare(X left, X right) {
return left.compareTo(right);
}
};
}

List to TreeSet conversion produces: "java.lang.ClassCastException: MyClass cannot be cast to java.lang.Comparable"

List<MyClass> myclassList = (List<MyClass>) rs.get();
TreeSet<MyClass> myclassSet = new TreeSet<MyClass>(myclassList);
I don't understand why this code generates this:
java.lang.ClassCastException: MyClass cannot be cast to java.lang.Comparable
MyClass does not implement Comparable. I just want to use a Set to filter the unique elements of the List since my List contains unncessary duplicates.
Does MyClass implements Comparable<MyClass> or anything like that?
If not, then that's why.
For TreeSet, you either have to make the elements Comparable, or provide a Comparator. Otherwise TreeSet can't function since it wouldn't know how to order the elements.
Remember, TreeMap implements SortedSet, so it has to know how to order
the elements one way or another.
You should familiarize yourself with how implementing Comparable
defines natural ordering for objects of a given type.
The interface defines one method, compareTo, that must return a negative integer, zero, or a positive integer if this object is less than, equal to, or greater than the other object respectively.
The contract requires that:
sgn(x.compareTo(y)) == -sgn(y.compareTo(x))
it's transitive: x.compareTo(y)>0 && y.compareTo(z)>0 implies x.compareTo(z)>0
x.compareTo(y)==0 implies that sgn(x.compareTo(z)) == sgn(y.compareTo(z)) for all z
Additionally, it recommends that:
(x.compareTo(y)==0) == (x.equals(y)), i.e. "consistent with equals
This may seem like much to digest at first, but really it's quite natural with
how one defines total ordering.
If your objects can not be ordered one way or another, then a TreeSet wouldn't make sense. You may want to use a HashSet instead, which have its own contracts. You are likely to be required to #Override hashCode() and equals(Object) as appropriate for your type (see: Overriding equals and hashCode in Java)
If you don't pass an explicit Comparator to a TreeSet, it will try to compare the objects (by assuming they are Comparable). And if they aren't Comparable, it cannot compare them, so this exception is thrown!
TreeSets are sorted sets and require either objects to be Comparable or a Comparator to be passed in to determine how to sort the objects in the Set.
If you just want the set to remove duplicates, used a HashSet, although that will shuffle the order of the objects returned by the Iterator in ways that appear random.
But if you want to preserve the order somewhat, use LinkedHashSet, that will at least preserve the insertion order of the list.
TreeSet is only appropriate if you need the Set sorted, either by the Object's implementation of Comparable or by a custom Comparator passed to the TreeSet's constructor.

Categories