Why is Java 'Comparable' better than just using a compareTo method? - java

I see that Comparable interface allowed implementation of just the compareTo method. So why do we even need this interface? Why can't we simply define and declare the method in any class we want, without having to implement the Comparable interface?
I understand that this is correct: SortedSet<String> exampleSet = new TreeSet<String>(); <-- TreeSet implements SortedSet interface. So if I have a class called "Date" that implements Comparable, is this correct: Comparable<Date> example = new Date<Date>();. If yes, what exactly do I get? I mean what kind of object do I get? What properties does it have? If not, why not?

Why can't we simply define and declare the method in any class we want, without having to implement the Comparable interface?
How would you expect a sorting method to work in that case?
It's really handy to be able to sort any collection where the elements are all comparable with each other - and an interface is the way to express that.
is this correct: Comparable<Date> example = new Date<Date>();
No, not unless Date itself were generic. You could write:
Comparable<Date> example = new Date();
... but it would be odd to do so. Normally Comparable is used by code which wants to compare existing objects - so it would fetch values from a collection and compare them with each other, for example.

Why can't we simply define and declare the method in any class we
want, without having to implement the Comparable interface?
Some Collections like TreeMap, need to compare two objects, even for a simple add() operation. Such a tree needs that to internally put "smaller" object in the left tree, and bigger ín the right subtree (a bit simplified).
Because such a generic Collection (like TreeMap), is designed to work for all Objects, the Object, then must know how to perfrom a compareTo().
Other Collections like HashMaps do not need that the Objects implement Comparable (They use hashcode())

Related

What is the difference between Collection and AbstractCollection in Java?

Edit: what i am actually meant to ask about is why do we need an abstract class, a hash class, etc implementing interfaces like map, set and collection?? What is the difference between those (abstractmap, hashmap, map) and why do they need to be interfaces?
If you want to implement a collection, it is easier to extend AbstractCollection which has already some methods of Collection implemented, than to implement the whole Collection interface.
From documentation of AbstractCollection:
This class provides a skeletal implementation of the Collection interface, to minimize the effort required to implement this interface.

What is point of implementing the Comparable interface in my classes?

I don't get the point of implementing the Comparable interface, since I can't use the comparison operators <, <=, >=, and > for my custom classes like I would be able to with operator overriding in languages like C++; I still have to call the compareTo method directly.
I could write my own boolean methods like isEqual or bigger, which would be just as useful, if not more so, than the compareTo method.
Am I missing something? What is the point of implementing it?
The Comparable interface provides a means of communication to the implemented sorting algorithms, which would be impossible using custom methods for comparison.
The point of implementing Comparable is being able to sort arrays, Collections, etc... based on different criteria.
Other classes can take a parameter of type Comparable. They will not know your special methods, but they know the interface and can use it if implemented.
As an example, the method Collections.sort() can make use of an Comparable: http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#sort(java.util.List,%20java.util.Comparator)

What isn't comparable by the Comparable class?

I know that this class compares two objects in a class(e.g. two Strings), but what types aren't comparable using this class?
That's not quite how it works. Comparable is an interface that any class may choose to implement in order to indicate that instances of the class may be compared using the class' compareTo() method. So you can choose to implement this interface in any class you create yourself (however, you must write the code for compareTo() yourself, since Java doesn't know how to compare your objects in a meaningful manner).
Some built-in classes implement Comparable and others don't - there might be a list somewhere, but it would be way too long for an SO answer. If you are wondering about whether a specific class implements compareTo(), check its documentation (and see if the comparison does what you expect) or simply try to call that method. If there is a built-in or third-party class that does not implement Comparable, you need to create a Comparator instead in order to compare them.
A Comparator may compare anything you wish, because you are the one who decides how it should work.
Actually, you can compare everything in Java.
For instance, you have a class X, which is incomparable. You can make this class an attribute to another class C and make C comparable, override its compareTo() method.
For example, it doesn't make sense to compare Colors
This is right. Even though it doesn't make sense, you can. Here is the answer for the question:
Which color is brighter?
public class ComparableColor implements Comparable<ComparableColor>
{
Color color;
public ComparableColor(Color color)
{
this.color = color;
}
#Override
public int compareTo(ComparableColor c)
{
return c.color.getAlpha() - this.color.getAlpha();
}
}
For example, it doesn't make sense to compare Colors, so this class doesn't implement the Comparable interface. Now, if you want a list of all classes that don't implement Comparable, I don't think there is one out there.

Can Comparator compare two objects of different type?

I have two objects of classes Person and Employee.
Both classes have common attribute age.
And I have added few objects of both theses classes to an Arraylist and now I want two write one Comparator and pass it to sort method of Collections class.
And want the list to be sorted on the basis of age.
I am trying this just for getting more clarity on use of Comparable and Comparator in Java.
EDIT:
Reason Why I was asking this question was that I was not clear about Comparator and Comparable.
I read somewhere that If Class implements Comparable then it can not be compared against objects of other classes (Because of Class cast exception).
Now if I create relation ship in Employee and Person then there is no need to implement Comparator (Unless I want to do sorting on the basis of name or other common attribute of these classes).
Once Again, I have asked this question to get more clarity on Comparator and Comparable.
Till now, What I have been able to understand is that If I want to do sorting on more than one parameters then I should implement Comparator and pass it to Collections.srot().
Or If I don't have control over the Class of object being sorted, then custom sorting I should implement Comparator.
(Correct me if I am wrong or I am missing something)
EDIT
I think now I understand the use of Comparable and Comparator.
To make sure I got the right concepts, here is what I understand:
If I want to compare two objects of different classes (and having no relation ) then I should use raw comparator and override the compare method.
Another reason why somebody would implement Comparator instead of Comparable is
to have flexibility in sorting.
And what I understand from natural sorting is the logic implemented by Class in CompareTo method.
Hope I am correct with all these points.
You can define an interface called Ageable and Employee and Person can implement this interface. Also you can define an abstract class (and Employee and Person will be inherited from the abstract class) with the same effect. Note that you can also use a normal class for this reason, you can do whatever you need.
Also, if there is no reason to say that an Employee is not a Person (for instance robots are working at the office) then Employee can be inherited from Person.
I would make an Employee a sub-class of Person. (Assuming all your employees are people) Then you can create a Comparator<Person>
You should create an interface AgeProvider:
public interface AgeProvider {
int getAge();
}
Both Person and Employee should implement AgeProvider. Now you can implement a Comparator that compares 2 AgeProvider.

What's the difference between these two java variable declarations?

public class SomeClass {
private HashSet<SomeObject> contents = new HashSet<SomeObject>();
private Set<SomeObject> contents2 = new HashSet<SomeObject>();
}
What's the difference? In the end they are both a HashSet isn't it? The second one looks just wrong to me, but I have seen it frequently used, accepted and working.
Set is an interface, and HashSet is a class that implements the Set interface.
Declaring the variable as type HashSet means that no other implementation of Set may be used. You may want this if you need specific functionality of HashSet.
If you do not need any specific functionality from HashSet, it is better to declare the variable as type Set. This leaves the exact implementation open to change later. You may find that for the data you are using, a different implementation works better. By using the interface, you can make this change later if needed.
You can see more details here: When should I use an interface in java?
Set is a collection interface that HashSet implements.
The second option is usually the ideal choice as it's more generic.
Since the HashSet class implements the Set interface, its legal to assign a HashSet to a Set variable. You could not go the other way however (assign a Set to a more specific HashSet variable).
Set is an interface that HashSet implements, so if you do this:
Set<E> mySet = new HashSet<E>();
You will still have access to the functionality of HashSet, but you also have the flexibility to replace the concrete instance with an instance of another Set class in the future, such as LinkedHashSet or TreeSet, or another implementation.
The first method uses a concrete class, allowing you to replace the class with an instance of itself or a subclass, but with less flexibility. For example, TreeSet could not be used if your variable type was HashSet.
This is Item 52 from Joshua Bloch's Effective Java, 2nd Edition.
Refer to Objects by their interfaces
... You should favor the use of interfaces rather than classes to refer to objects. If appropriate interface types exist, then parameters, return values, variables, and fields should all be declared using interface types. The only time you really need to refer to an object's class is when you're creating it with a constructor...
// Usually Good - uses interface as type
List<T> tlist = new Vector<T>();
// Typically Bad - uses concrete class as type!
Vector<T> vec = new Vector<T>();
This practice does carry some caveats - if the implementation you want has special behavior not guaranteed by the generic interface, then you have to document your requirements accordingly.
For example, Vector<T> is synchronized, whereas ArrayList<T> (also an implementer of List<T>) does not, so if you required synchronized containers in your design (or not), you would need to document that.
One thing worth to mention, is that interface vs. concrete class rule is most important for types exposed in API, eg. method parameter or return type. For private fields and variables it only ensures you aren't using any methods from concrete implementation (i.e. HashSet), but then it's private, so doesn't really matter.
Another thing is that adding another type reference will slightly increase size of your compiled class. Most people won't care, but these things adds up.

Categories