I've been trying to learn the comparable class for sometime now, I know the correct syntax and the how it is used in most cases. Such as:
int result = ObjectA.compareTo(ObjectB);
would return a value of 0 if both object is the same; a negative value if object A is less then object B ,or a positive value if A is greater then B.
However when I go to actually write a program that uses the compareTo method, the compiler is saying that it can not find the compareTo method.
my question is: Do I have to directly inherit from the Comparable class in order to use the compareTo method? only reason I'm asking is because you do not have to explicitly inherit methods like toString or equals...because everything inherit from object. Where does CompareTo fall under?
You need to implement the Comparable interface:
public class MyClass implements Comparable<MyClass>
and then declare the compareTo() method:
public int compareTo(MyClass myClass){
//compare and return result
}
Comparable is an interface, not a class. So you would implement the interface, not subclass the class. Additionally, implementing the interface means implementing the compareTo method yourself in your implementing class.
First, it will only work in instances. Don't know if your compare is comparing objects or the classes itself because of your naming. I will assume you are using objects :)
The class you want to compare using #compareTo MUST implement Comparable. Another way to achieve this without having to implement Comparable is providing your sort method a Comparator expecting your class.
Comparable is an interface so you do not "inherit" it (extends), but implement it (implements).
You can write your own compareTo method in your class without specifying the Comparable interface, but then the methods in the API won't know if your object meets the contract that Comparable enforces. So, you won't be able to use methods like Arrays.sort() and the like that expect to work with objects that do enforce Comparable.
If you want the objects of your class A compared, possibly because you like to sort a list of those objects, you need to make the class A implement Comparable interface.
Once the class A implements Comparable it must implement and define the behavior of compareTo, which is essentially how you want two objects of class A be compared.
It it this method where you can decide which fields of the class A take part in evaluating the lesser- or greaterness of an object.
Related
How to make two objects in Java comparable using "<" or ">"
e.g.
MyObject<String> obj1= new MyObject<String>(“blablabla”, 25);
MyObject<String> obj2= new MyObject<String>(“nannaanana”, 17);
if (obj1 > obj2)
do something.
I've made MyObject class header as
public class MyObject<T extends Comparable<T>> implements Comparable<MyObject<T>>
and created method Comp but all the gain I got is now I can use "sort" on the list of objects, but how can I compare two objects to each other directly? Is
if(obj1.compareTo(obj2) > 0)
do something
the only way?
You cannot do operator overloading in Java. This means you are not able to define custom behaviors for operators such as +, >, <, ==, etc. in your own classes.
As you already noted, implementing Comparable and using the compareTo() method is probably the way to go in this case.
Another option is to create a Comparator (see the docs), specially if it doesn't make sense for the class to implement Comparable or if you need to compare objects from the same class in different ways.
To improve the code readability you could use compareTo() together with custom methods that may look more natural. For example:
boolean isGreaterThan(MyObject<T> that) {
return this.compareTo(that) > 0;
}
boolean isLessThan(MyObject<T> that) {
return this.compareTo(that) < 0;
}
Then you could use them like this:
if (obj1.isGreaterThan(obj2)) {
// do something
}
Using Comparable.compareTo(T) is the only option (or Comparator). The interface only defines that one method (while Comparator adds equals), and it compares this object with the specified object for order. Further, Java does not permit operator overloading (so you won't be able to directly change the operand used for invoking that method; or in fact modify the interface).
It is not the only way. You can implement a Comparator as well. Comparator uses compare() method as oppose to Comparable which uses compareTo() method.
The reason you can't use > or < to compare objects directly is because Java won't know which variable you want to use for the comparison (as there might exist more than one variable in the object).
In order to compare objects, those objects must be comparable. You need to define and tell Java how you want to compare them.
Java collection provides a sort method. However some school does give assignment of asking you to write you own sort methods which ultimately still uses the compareTo() for comparison.
You can take a look on the subtle differences between Comparable vs Comparator here: What is the difference between compare() and compareTo()?
I think it is also worth mentioning that, by default Java compares String (objects) in a lexicographical order if you did not override the compareTo() method.
I would advocated that readability must be a primer for us as developers.
Apache Commons Lang (commons-lang) provides a simple fluent utility which reads a lot clearer:
if (is(obj1).greaterThan(obj2)) {
// do something
}
Note: is is shorthand for ComparableUtils.is which can be imported the following this static import statement:
import static org.apache.commons.lang3.compare.ComparableUtils.is;
I wanted to ask why we use the comparable interface in java? Wouldn't it be simpler to just make the compareTo method without using the comparable interface?
Instead of doing this:
//some class that implements comparable
public int compareTo(someClass someInstanceOfThatClass) {
// do stuff that returns -1,0,or 1
}
Why can't we just do this:
//some class that does NOT implement comparable, but we still
//make a compareTo method
public int compareTo(someClass someInstanceOfThatClass) {
// do stuff that returns -1,0, or 1
}
I guess my question is why do we bother implementing comparable, if we could just make a compareTo method without being forced to by some interface (comparable)?
Comparable is an interface, hence it imposes a contract that others may follow. For example, calling Collections.sort(list) only works if the elements are instances of Comparable, and internally relies on the compareTo method to implement the sorting.
Java's type system is nominal, not structural, so simply having the method required by the interface is not enough to implement it; you also have to declare that the class implements the interface. In some other languages such as Typescript, having the method with the right signature would be enough, but Java is not like that.
If you are only calling the compareTo method from your own code then this may not matter, but if you are using classes or methods from the standard library or from other libraries which take Comparable things as arguments, then your class will need to implement the interface so you can pass your objects to them.
I think it returns to the innate concept of the interface.
You always sure that every class which has implemented Comparable interface, has ability to be compared and sometimes you need this assurance.
For example if you have a method that have a parameter with Comparable type, then you are sure that comapreTo is implemented with that parameter and this parameter issemantically comparable.
But whitout interface you can't get this assurance.
All beginners like myself, always get confused to see a method returns an object of an interface type, because interfaces have abstract methods, thus cannot be instantiated.
I finally figured out a way to understand this:
((when we say that a method returns an object of an interface type, we are actually implicitly saying that the method in fact returns an object/instance of some class that implements that interface, but in most cases that class is unknown because it is declared as anonymous in the implementation of the method. Thus, we refer to the returned object as being of that interface type.)).
Is this explanation correct ?
"...when we say that a method returns an object of an interface type, we are actually implicitly saying that the method in fact returns an object/instance of some class that implements that interface..." - It is correct, but we are saying it explicitly.
The second part of your definition is quite not correct, as #Jon Skeet pointed out. Applying anonymous class in the implementation is a very specific case. Generally, returning an interface gives you more freedom:
It is possible to change implementation of the method to return another object that implements the same interface, without changing code that uses this method.
You leave possibility for extending classes to override the method, so that it returns another object that implements the same interface. Here you can actually change the return type. If method of the base class returned concrete class, e.g., ArrayList, overridden method would have to also return ArrayList or its subclass.
The rule of thumb is the following. If concrete class implements an interface and there is no benefit in returning a concrete class object, e.g., ArrayList, return an interface - List, Collection. This will enhance maintainability of your code, i.e., the code will be easier to change in future.
It's my birthday at the end of this month, so I've added a new method to all my friends and family:
public Present givePresent{
//code to select an appropriate and sufficiently expensive present
return present;
}
There's two things I could do here. I could write a Present class and ensure that all possible presents extend it. But we could run in to all sorts of problems here: BatmanComic already inherits from ComicBook for example, so we'd have to move further and further up the tree until Present is basically indistinguishable from Object. The other way is to look at what is actually happening here. I'm looking to receive something that fits in to a specific category and, in short, Java has two ways of doing that. Inheritance and Interfaces. Creating Present as an interface is achieving exactly the same goal as creating it as an abstract superclass but avoids all problems of multiple inheritance. This way all I have to do is write an interface:
public interface Present{
}
and make sure all the socks and books and whatever implement that.
I see code like this
class A implements Comparable<A> {
}
What does this mean, what are the advantages and disadvantages of it?
It means that class is committed to respond to the methods defined by the "interface" Comparable.
The advantage you have with this ( and any other "implements" declaration ) it that you can "abstract" the type of the object and code to the interface instead.
Consider this
class A implements Comparable {
....
}
class B implements Comparable {
....
}
class C implements Comparable {
....
}
You then may code something that can use Comparable instead of a specific type:
public void doSomethingWith( Comparable c ) {
c.compareTo( other ); // something else...
}
And invoke it like:
doSomethingWith( new A() );
doSomethingWith( new B() );
doSomethingWith( new C() );
Because you don't really care what the type of the class is, you just care it does implement the interface.
This ( program to the interface rather to the implementation ) is one of the most powerful techniques in OO programming world, because it promotes low-coupling.
Implementing a comparable interface means that A can be compared with other instances of A.
Many operations in java that involve sorting use the methods defined in the Comparable interface to determine if instances of A are greater then less or equal to other instances.
By implementing these methods you are able to use a lot of handy features such as java sort, use instances of A as keys for binary trees, and more.
It means that class A can be sorted using the Comparable compareTo method:
A a1 = new A(1);
A a2 = new A(3);
// -1, 0, or 1 depending on whether a2 is less than, equal to, or greater than a1
int order = a1.compareTo(a2);
Comparable uses the natural ordering for your class.
Another way to go since Java 5 is Comparator. You can pass this object around and have more than one way to compare and sort the target class. For example, sometimes you might want to sort a Name class by first name, other times by last name. Comparable only gives you one way to do it, but you can have several Comparator instances.
It means that the class is one which can be operated on by functions which expect their arguments to be objects that can be compared with other objects of the same type (such as the pre-defined sorting functionality for lists).
Implementing the Comparable interface means that the class supports certain functions which the interface requires (specifically, the compareTo() method), that the sorting (or other) operations being performed on the class will utilize to do their work without having to care about the rest of the class.
For more details:
http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Comparable.html
In addition to what everyone else said, by implementing an interface (or extending a class), you get compiler enforcement of the contract of the supertype. In the case of 'Comparable', that means that you get a compiler error if you fail to implement the 'int compareTo(A anA)' method in the implementing class. Adding the annotation '#Override' to the implementing method provides even more compile-time safety; if you fail to implement the method with the right signature the compiler will tell you. Compile-time errors are much, much easier and cheaper to fix than run-time errors. Furthermore, implementing an interface allows any instance of an implementing class to be treated as the interface type for methods (and constructors) that take the interface type as an argument or generic parameter. For example, the 'java.util.Collections.max(Collection coll)' method takes a collection whose base type must extend 'Comparable'.
http://download.oracle.com/javase/7/docs/api/java/util/Collections.html#max(java.util.Collection)
It means that objects of this class can be easily sorted in collections because they can be compared to each other. The other option is to implement a Comparator which is a class responsible for sorting other classes. The Comparable puts the sorting logic directly in the class to be sorted; the Comparator puts the sorting logic in a different class.
What is the difference between Java's compare() and compareTo() methods? Do those methods give same answer?
From JavaNotes:
a.compareTo(b):
Comparable interface : Compares values and returns an int which tells if the values compare less than, equal, or greater than.
If your class objects have a natural order, implement the Comparable<T> interface and define this method. All Java classes that have a natural ordering implement Comparable<T> - Example: String, wrapper classes, BigInteger
compare(a, b):
Comparator interface : Compares values of two objects. This is implemented as part of the Comparator<T> interface, and the typical use is to define one or more small utility classes that implement this, to pass to methods such as sort() or for use by sorting data structures such as TreeMap and TreeSet. You might want to create a Comparator object for the following:
Multiple comparisons. To provide several different ways to sort something. For example, you might want to sort a Person class by name, ID, age, height, ... You would define a Comparator for each of these to pass to the sort() method.
System class To provide comparison methods for classes that you have no control over. For example, you could define a Comparator for Strings that compared them by length.
Strategy pattern To implement a Strategy pattern, which is a situation where you want to represent an algorithm as an object that you can pass as a parameter, save in a data structure, etc.
If your class objects have one natural sorting order, you may not need compare().
Summary from http://www.digizol.com/2008/07/java-sorting-comparator-vs-comparable.html
Comparable
A comparable object is capable of comparing itself with another object.
Comparator
A comparator object is capable of comparing two different objects. The class is not comparing its instances, but some other class’s instances.
Use case contexts:
Comparable interface
The equals method and == and != operators test for equality/inequality, but do not provide a way to test for relative values.
Some classes (eg, String and other classes with a natural ordering) implement the Comparable<T> interface, which defines a compareTo() method.
You will want to implement Comparable<T> in your class if you want to use it with Collections.sort() or Arrays.sort() methods.
Defining a Comparator object
You can create Comparators to sort any arbitrary way for any class.
For example, the String class defines the CASE_INSENSITIVE_ORDER comparator.
The difference between the two approaches can be linked to the notion of:
Ordered Collection:
When a Collection is ordered, it means you can iterate in the collection in a specific (not-random) order (a Hashtable is not ordered).
A Collection with a natural order is not just ordered, but sorted. Defining a natural order can be difficult! (as in natural String order).
Another difference, pointed out by HaveAGuess in the comments:
Comparable is in the implementation and not visible from the interface, so when you sort you don't really know what is going to happen.
Comparator gives you reassurance that the ordering will be well defined.
compareTo() is from the Comparable interface.
compare() is from the Comparator interface.
Both methods do the same thing, but each interface is used in a slightly different context.
The Comparable interface is used to impose a natural ordering on the objects of the implementing class. The compareTo() method is called the natural comparison method. The Comparator interface is used to impose a total ordering on the objects of the implementing class. For more information, see the links for exactly when to use each interface.
Similarities:
Both are custom ways to compare two objects.
Both return an int describing the relationship between two objects.
Differences:
The method compare() is a method that you are obligated to implement if you implement the Comparator interface. It allows you to pass two objects into the method and it returns an int describing their relationship.
Comparator comp = new MyComparator();
int result = comp.compare(object1, object2);
The method compareTo() is a method that you are obligated to implement if you implement the Comparable interface. It allows an object to be compared to objects of similar type.
String s = "hi";
int result = s.compareTo("bye");
Summary:
Basically they are two different ways to compare things.
The methods do not have to give the same answers. That depends on which objects/classes you call them.
If you are implementing your own classes which you know you want to compare at some stage, you may have them implement the Comparable interface and implement the compareTo() method accordingly.
If you are using some classes from an API which do not implement the Comparable interface, but you still want to compare them. I.e. for sorting. You may create your own class which implements the Comparator interface and in its compare() method you implement the logic.
Using Comparator, we can have n number of comparison logic written for a class.
E.g.
For a Car Class
We can have a Comparator class to compare based on car model number. We can also have a Comparator class to compare based on car model year.
Car Class
public class Car {
int modelNo;
int modelYear;
public int getModelNo() {
return modelNo;
}
public void setModelNo(int modelNo) {
this.modelNo = modelNo;
}
public int getModelYear() {
return modelYear;
}
public void setModelYear(int modelYear) {
this.modelYear = modelYear;
}
}
Comparator #1 based on Model No
public class CarModelNoCompartor implements Comparator<Car>{
public int compare(Car o1, Car o2) {
return o1.getModelNo() - o2.getModelNo();
}
}
Comparator #2 based on Model Year
public class CarModelYearComparator implements Comparator<Car> {
public int compare(Car o1, Car o2) {
return o1.getModelYear() - o2.getModelYear();
}
}
But this is not possible with the case of Comparable interface.
In case of Comparable interface, we can have only one logic in compareTo() method.
Comparable interface contains a method called compareTo(obj) which takes only one argument and it compares itself with another instance or objects of the same class.
Comparator interface contains a method called compare(obj1,obj2) which takes two arguments and it compares the value of two objects from the same or different classes.
compareTo(T object)
comes from the java.lang.Comparable interface, implemented to compare this object with another to give a negative int value for this object being less than, 0 for equals, or positive value for greater than the other. This is the more convenient compare method, but must be implemented in every class you want to compare.
compare(T obj1, T obj2)
comes from the java.util.Comparator interface, implemented in a separate class that compares another class's objects to give a negative int value for the first object being less than, 0 for equals, or positive value for greater than the second object. It is needed when you cannot make a class implement compareTo() because it is not modifiable. It is also used when you want different ways to compare objects, not just one (such as by name or age).
The relationship of the object having this method and its collaborators is different.
compareTo() is a method of the interface Comparable, so it is used to compare THIS instance to another one.
compare() is a method of the interface Comparator, so it is used to compare two different instances of another class with each other.
If you will, implementing Comparable means that instances of the class can be easily compared.
Implementing Comparator means, that instances are suited to compare different objects (of other classes).
The main difference is in the use of the interfaces:
Comparable (which has compareTo()) requires the objects to be compared (in order to use a TreeMap, or to sort a list) to implement that interface. But what if the class does not implement Comparable and you can't change it because it's part of a 3rd party library? Then you have to implement a Comparator, which is a bit less convenient to use.
compareTo() is called on one object, to compare it to another object.
compare() is called on some object to compare two other objects.
The difference is where the logic that does actual comparison is defined.
One more point:
Comparable is used to define a default ordering for objects within a class
Comparator is used to define a custom ordering to be passed to a method.
comparator-vs-comparable
When you want to sort a List which include the Object Foo, the Foo class has to implement the Comparable interface, because the sort methode of the List is using this methode.
When you want to write a Util class which compares two other classes you can implement the Comparator class.
Employee Table
Name, DoB, Salary
Tomas , 2/10/1982, 300
Daniel , 3/11/1990, 400
Kwame , 2/10/1998, 520
The Comparable interface allows you to sort a
list of objects eg Employees with reference to one primary field – for
instance, you could sort by name or by salary with the CompareTo() method
emp1.getName().compareTo(emp2.getName())
A more flexible interface for such requirements is provided by
the Comparator interface, whose only method is compare()
public interface Comparator<Employee> {
int compare(Employee obj1, Employee obj2);
}
Sample code
public class NameComparator implements Comparator<Employee> {
public int compare(Employee e1, Employee e2) {
// some conditions here
return e1.getName().compareTo(e2.getName()); // returns 1 since (T)omas > (D)an
return e1.getSalary().compareTo(e2.getSalary()); // returns -1 since 400 > 300
}
}
There is a technical aspect that should be emphasized, too. Say you need comparison behavior parameterization from a client class, and you are wondering whether to use Comparable or Comparator for a method like this:
class Pokemon {
int healthPoints;
int attackDamage;
public void battle (Comparable<Pokemon> comparable, Pokemon opponent) {
if (comparable.compareTo(opponent) > 0) { //comparable needs to, but cannot, access this.healthPoints for example
System.out.println("battle won");
} else {
System.out.println("battle lost");
}
}
}
comparable would a lambda or an object, and there is no way for comparable to access the fields of this Pokemon. (In a lambda, this refers to the outer class instance in the lambda's scope, as defined in the program text.) So this doesn't fly, and we have to use a Comparator with two arguments.
Use Comparable interface for sorting on the basis of more than one value like age,name,dept_name...
For one value use Comparator interface
Important Answar
String name;
int roll;
public int compare(Object obj1,Object obj2) { // For Comparator interface
return obj1.compareTo(obj1);
}
public int compareTo(Object obj1) { // For Comparable Interface
return obj1.compareTo(obj);
}
Here in return obj1.compareTo(obj1) or return obj1.compareTo(obj) statement
only take Object; primitive is not allowed.
For Example
name.compareTo(obj1.getName()) // Correct Statement.
But
roll.compareTo(obj1.getRoll())
// Wrong Statement Compile Time Error Because roll
// is not an Object Type, it is primitive type.
name is String Object so it worked.
If you want to sort roll number of student than use below code.
public int compareTo(Object obj1) { // For Comparable Interface
Student s = (Student) obj1;
return rollno - s.getRollno();
}
or
public int compare(Object obj1,Object obj2) { // For Comparator interface
Student s1 = (Student) obj1;
Student s2 = (Student) obj2;
return s1.getRollno() - s2.getRollno();
}