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)
Related
I am implementing equals method for a class, which has a member of a Functional Interface type. I do not have a separate class for the concrete implementation of the interface, and I use lambda expression to create and set the interface variable. I want the equals method of the class to take into consideration, the code, which was provided via lambda expression. Different implementations must must not return equal. Is there a way to achieve this properly? Since I did not find any links related to this requirement I am doubting whether such a practice is recommended, even if it is possible to achieve the same. What is the best thing to do?
Why does the Collection interface have equals(Object o) and hashCode(), given that any implementation will have those by default (inherited from Object) ?
From the Collection JavaDoc:
While
the Collection interface adds no stipulations to the general contract
for the Object.equals, programmers who implement the Collection
interface "directly" (in other words, create a class that is a
Collection but is not a Set or a List) must exercise care if they
choose to override the Object.equals. It is not necessary to do so,
and the simplest course of action is to rely on Object's
implementation, but the implementor may wish to implement a "value
comparison" in place of the default "reference comparison." (The List
and Set interfaces mandate such value comparisons.)
The general contract for the Object.equals method states that equals
must be symmetric (in other words, a.equals(b) if and only if
b.equals(a)). The contracts for List.equals and Set.equals state that
lists are only equal to other lists, and sets to other sets. Thus, a
custom equals method for a collection class that implements neither
the List nor Set interface must return false when this collection is
compared to any list or set. (By the same logic, it is not possible to
write a class that correctly implements both the Set and List
interfaces.)
and
While the Collection interface adds no stipulations to the general contract for the Object.hashCode method, programmers should take note that any class that overrides the Object.equals method must also override the Object.hashCode method in order to satisfy the general contract for the Object.hashCode method. In particular, c1.equals(c2) implies that c1.hashCode()==c2.hashCode().
To answer your specific question: why does it have these methods? It's done simply for convenience to be able to include Java Docs giving hints as to what implementers should do with these methods (e.g. comparing equality of values rather than references).
To add to the other great answers. In the Collections interface, the equals method is defined in that interface to make some decisions in the way equaling two instances of collection should work. From the JAVA 8 documentation:
More generally, implementations of the various Collections Framework
interfaces are free to take advantage of the specified behavior of
underlying Object methods wherever the implementor deems it
appropriate.
So you don’t add methods from the Object class for any other reason that giving more definitiveness to the java doc. This is the reason why you don’t count those methods in the abstract methods in the abstract methods of an interface.
Moreover, in JAVA 8, along the same line of reasoning, default methods from the Object class are not allowed and will generate a compile error. I believe it’s was done to prevent this type of confusion. So if you try to create a default method called hashCode(), for example, it will not compile.
Here is a more in-depth explanation for this behavior in JAVA 8 from the Lambda FAQ:
An interface cannot provide a default implementation for any of the
methods of the Object class. This is a consequence of the “class wins”
rule for method resolution: a method found on the superclass chain
always takes precedence over any default methods that appear in any
superinterface. In particular, this means one cannot provide a default
implementation for equals, hashCode, or toString from within an
interface.
This seems odd at first, given that some interfaces actually define
their equals behavior in documentation. The List interface is an
example. So, why not allow this?
One reason is that it would become more difficult to reason about when
a default method is invoked. The current rules are simple: if a class
implements a method, that always wins over a default implementation.
Since all instances of interfaces are subclasses of Object, all
instances of interfaces have non-default implementations of equals,
hashCode, and toString already. Therefore, a default version of these
on an interface is always useless, and it may as well not compile.
Another reason is that providing default implementations of these
methods in an interface is most likely misguided. These methods
perform computations over the object’s state, but the interface, in
general, has no access to state; only the implementing class has
access to this state. Therefore, the class itself should provide the
implementations, and default methods are unlikely to be useful.
Just to add to the great answers above, it makes sense to have the 'equals' or `hashCode' methods in this scenario:
Collection<Whatever> list1 = getArrayList();
Collection<Whatever> list2 = getAnotherArrayList();
if(list1.equals(list2)){
// do something
}
In the absence of the equals method in the interface, we'll be forced to use concrete types, which is generally not a good practice :
ArrayList<Whatever> list1 = getArrayList();
ArrayList<Whatever> list2 = getAnotherArrayList();
if(list1.equals(list2)){
// do something
}
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.
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())
The Comparator interface has its own equals() method. Any class will get equals() by default through Object class. What is the need to have equals() method inside an interface?
Comparator refines the contract of Object.equals: It has to satisfy the constraints set out by Object.equals and then some.
Additionally, this method can return true only if the specified object is also a comparator and it imposes the same ordering as this comparator. Thus, comp1.equals(comp2) implies that sgn(comp1.compare(o1, o2))==sgn(comp2.compare(o1, o2)) for every object reference o1 and o2.
Declaring an equals inside Comparator allows you to document this in the form of javadoc.
Note that the documentation of the API also serves as the contract, so it's not just cosmetics here. It's explicit constraints that other code and your code can rely on.
In similar situations where you have less established methods, it may also serve as documenting an intent. I.e., Interface.method should be there, regardless of how its super interfaces evolves.
From the Java documentations, the reason why Comparator has it's own equals() method:
However, overriding this method may, in some cases, improve performance by allowing programs to determine that two distinct comparators impose the same order.
Read its javadoc. It's there only to explain what equals() must return if you choose to override it in a class implementing Comparator. You might think that no comparator can be equal to any other, but it's not the case. You might think that two comparators are equal if they return the same thing for any arguments, but it's not the case. The javadoc explains that two comparators are equal if they impose the same ordering, whatever the arguments given. The javadoc also says:
Note that it is always safe not to override Object.equals(Object)
Most of the time, you don't override equals() in comparators.
from the docs:
it is always safe not to override Object.equals(Object). However, overriding this method may, in some cases, improve performance by allowing programs to determine that two distinct comparators impose the same order.
Technically, the declaration of the method is redundant (the compiler does not care), but...
Declaring the equals method in this interface makes it part of the contract between caller and different Comparators and allows it to specify/extend its semantics.
It specifies that two Comparators are equal only if they impose the same ordering with their compare() method. This extends the semantics of Object.equals() and must therefore be documented in the interface.
Putting an Object method in an interface declaration allows Javadoc
declaration of the meaning equals is required to have in classes that
implement the interface.
Comparator interface have their own equals() method
Well,. first of all, it should be clear that whenever you implement Comparable interface you should provide your program to decide when objects are equal, less or greater.
I am quite confuse about have equals() inside Comparator. Any class will get equals() by default through Object class.
The equals() method implementation u inherit from Object class only checks whether the two referances point to the same object or not. It dosn't apply any comparison. It's you who will provide in your class (or possibly in your Interface) the criteria for objects to be equal.
Then what is need to have equals() method inside an interface?
Obviously , whenever you implement when objects are less , greater than you must implement when they are equal. so rather than relying on default Object equals() method you should provide your logic to check equality
The equals() method in Comparator is provided to force a user implementing the Comparator interface to implement equals() with some additional rules and constraints in addition to the ones already applied on equals() from Object.
The additional rule being:
This method must obey the general contract of Object.equals(Object).
Additionally, this method can return true only if the specified object
is also a comparator and it imposes the same ordering as this
comparator. Thus, comp1.equals(comp2) implies that
sgn(comp1.compare(o1, o2))==sgn(comp2.compare(o1, o2)) for every
object reference o1 and o2.