Java : Comparable vs Comparator
When your class implements Comparable, the compareTo
method of the class is defining the "natural" ordering of that object. That method is contractually obligated (though not demanded) to be in line with other methods on that object, such as a 0 should always be returned for objects when the .equals()
comparisons return true.
A Comparator is its own definition of how to compare two objects, and can be used to compare objects in a way that might not align with the natural ordering.
For example, Strings are generally compared alphabetically. Thus the "a".compareTo("b")
would use alphabetical comparisons. If you wanted to compare Strings on length, you would need to write a custom comparator.
In short, there isn't much difference. They are both ends to similar means. In general implement comparable for natural order, (natural order definition is obviously open to interpretation), and write a comparator for other sorting or comparison needs.
When to use Comparable and Comparator
I would say that an object should implement Comparable if that is the clear natural way to sort the class, and anyone would need to sort the class would generally want to do it that way.
If, however, the sorting was an unusual use of the class, or the sorting only makes sense for a specific use case, then a Comparator is a better option.
Put another way, given the class name, is it clear how a comparable would sort, or do you have to resort to reading the javadoc? If it is the latter, odds are every future sorting use case would require a comparator, at which point the implementation of comparable may slow down users of the class, not speed them up.
Java: Comparable vs Comparator - Memory & Performance
That answer is incorrect.
Adding implemented interfaces or methods does not influence the memory required for individual instances of a class.
First of all, conceptually it doesn't make sense.
Implemented interfaces and methods are per-class information. Two instances of the same class will always implement exactly the same interfaces and have the exact same methods. As such, it makes no sense for the JVM to store that information per-object.
Second, you can easily verify that with sample code like this:
public class MyClass implements Comparable<MyClass> {
private final long l;
MyClass(long l) {this.l = l;}
@Override
public int compareTo(MyClass o) {
return 0;
}
public static void main(String[] args) {
long l = 0;
try {
var list = new ArrayList<MyClass>();
while (true) {
list.add(new MyClass(l++));
}
} catch (OutOfMemoryError e) {
System.out.println("Created " + l + " objects before things went south ...");
}
}
}
Running this with -Xmx32m
using Java 11 will create about 200000 objects on each run for me (with slight variations, probably due to GC details).
Removing the Comparable
interface and/or the compareTo
method does not significantly change that value.
You can try adding additional fields or removing l
, which will change the number.
Difference between Comparable and Comparator?
Not really.Comparable
and Comparator
are generic interfaces that allow to compare instances of the type defined in the generic (subclasses included).
The main difference between them is that Comparable
is directly implemented in the class which you want to compare objects.
Consequently, if you have a single way to compare instances from a class, that is that you have a natural order for them, Comparable
is the right approach.
On the other hand, if you have multiple ways to compare instances from a class, Comparable
is not enough.
You should use Comparator
s instead (if it doesn't exist a natural order) or use both (if it exists a natural order and some other kinds of order).
Example where Comparator
can be useful in addition to Comparable
:
The String
class implements Comparable
by comparing two strings lexicographically.
Suppose you need to sort a List
of String
according to a different rule : their length.
You will need to define a Comparator<String>
that implements this rule such as :
public class StringLengthComparator implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
return Integer.compare(o1.length(), o2.length());
}
}
Now you could sort String
s by using their natural order (using Comparable
) :
List<String> strings = new ArrayList<>();
...
strings.sort();
But you could also use a specific Comparator<String>
:
strings.sort(new StringLengthComparator());
Or without creating any class with a lambda:
strings.sort((o1,o2)->Integer.compare(o1.length(), o2.length()));
Example where Comparator
should be used instead of Comparable
:
Suppose you have an Account
class that represents a bank account.
Functionally you don't have a natural order to sort them but you have instead multiple orders according to the client needs.
Making the class to implement Comparable
would not make sense. But creating distinct Comparator<Account>
would.
Case where only Comparator
can be used :
If you want to define a order for instances of a class which you cannot change the source code (JDK class or third party class), Comparator
is the way to follow.
When should a class be Comparable and/or Comparator?
The text below comes from Comparator vs Comparable
Comparable
A comparable object is capable of comparing itself with another object. The class itself must implements the java.lang.Comparable
interface in order to be able to compare its instances.
Comparator
A comparator object is capable of comparing two different objects. The class is not comparing its instances, but some other class’s instances. This comparator class must implement the java.util.Comparator
interface.
Why use comparable and comparator interface
A question such as "why use Comparator
or Comparable
rather than bubble sort?" really makes no sense. These are not alternatives to each other. Any sorting algorithm (including ones that you code yourself) needs a mechanism for defining the order of the objects. That is what the interfaces do: provide a mechanism for defining an ordering on objects.
If the question is "why use sorting methods built into the JDK rather than write your own?" then the answer is probably fairly obvious: it saves effort and complexity.
If the question is "when should you use Comparable
and when should you use Comparator
?" then I would suggest searching for one of the excellent primers on this topic. As a very simplified answer, Comparable
is used to define a natural (default) ordering for objects within a class while Comparator
is used to define a custom ordering to be passed to a method.
Note also that the Comparator
interface has many very powerful methods for defining comparisons. Very little needs to be done manually now. For example, if you have a Person
class you can sort a list with code such as:
Collection.sort(personList, Comparator
.comparingInt(Person::getAge)
.thenComparing(Person::getSurname));
In my view this code is better than the old mechanism of defining compareTo
methods in a class as it hides away the implementation details of returning arbitrary integers representing comparison between fields and makes the intention pretty obvious. In fact it's enough of an improvement on older methods that in my own code I tend to avoid natural orderings altogether unless the class has an inherent obvious order that can be naturally represented as the difference between two integers (e.g. a class defining temperature or heights).
in what way is a comparator superior to comparable?
Comparable
interface
The Comparable
interface defines a type's natural ordering. Suppose you have a list of String
or Integer
objects; you can pass that list to
Collections.sort(list);
and you will have a sorted list. How? Because String
and Integer
both implement Comparable
interface and the implementations of Comparable
interface provide a natural ordering. Its like the class definition saying - "If you find a collection of objects of my type, order them according to the strategy I have defined in the compareTo
method".
Now when you define your own type, you can define the natural ordering of the objects of your class by implementing the Comparable
interface. See the Java documentation for more information on object ordering.
Comparator
interface
The Comparator
interface describes how to define custom strategies for object ordering. Suppose we have a simple Person
type as below:
public class Person {
String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Now, by implementing the Comparator
interface, you can write different strategies to order the instances of your Person
type. For example, consider the two strategies for ordering Person
objects given below:
class StrategyOne implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getName().length() - p2.getName().length();
}
}
class StrategyTwo implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getName().compareTo(p2.getName());
}
}
Here, StrategyOne
will order Person
objects based on the length of their names, and StrategyTwo
will order Person
objects based on lexicographic ordering of their names.
The ways to implement Comparator
As you can see, the concrete strategy classes are stateless, hence all instances are functionally equivalent. So, we just need a single instance of any concrete strategy class. Thus, it should be a singleton. Using anonymous classes will create a new instance each time the call is executed. Consider storing the object in a private static final field and reusing it by using static factory methods to access them [Effective Java]. For example, you can reuse the above two concrete strategies as below:
class Strategies {
private static final Comparator<Person> PERSON_NAME_LENGTH_COMPARATOR = new StrategyOne();
private static final Comparator<Person> PERSON_NAME_LEXICAL_COMPARATOR = new StrategyTwo();
public static Comparator<Person> personNameLengthComparator(){
return PERSON_NAME_LENGTH_COMPARATOR;
}
public static Comparator<Person> personNameLexicalComparator(){
return PERSON_NAME_LEXICAL_COMPARATOR;
}
}
Summary
To summarize, the Comparable
interface is used to define the natural ordering of a class, and the Comparator
interface is used to define particular strategies for object ordering.
When should I use Comparator vs Comparable?
There's a substantial distinction between the use cases for Comparator
and Comparable
.
Implementing the Comparable
interface is suitable for objects that have a natural order in your domain model. I'm not sure whether animals have a natural order, but if it is the case from the perspective of how your application model the animals, that's fine - that's the way to go. Otherwise, your class should not implement Comparable
.
It's not something opinion-based, documentation clearly defines when these interfaces are intended to be used.
Comparable:
This interface imposes a total ordering on the objects of each class
that implements it. This ordering is referred to as the class's
natural ordering, and the class'scompareTo
method is referred to as
its natural comparison method.
Comparator:
Comparators can also be used to control the order of certain data structures (such as sorted sets or sorted maps), or to provide an ordering for collections of objects that don't have a natural ordering.
Another obvious distinction, that you can define as many flavors of comparators as you need. Which is handy when there's no one specific way to compare and sort the objects. And they must have more meaningful names than comparator
.
Personally, I don't see a huge harm in defining a couple of comparators as public static final
fields, as in your example. If you have a single class that manages the instances of this type - extract the comparators into that class, otherwise if these objects are ubiquitous and used in many places you can leave them right inside the POJO (that an opinion based part).
What is the difference between compare() and compareTo()?
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 theComparable<T>
interface and define this method. All Java classes that have a natural ordering implementComparable<T>
- Example:String
, wrapper classes,BigInteger
compare(a, b)
:
Comparator interface : Compares values of two objects. This is implemented as part of theComparator<T>
interface, and the typical use is to define one or more small utility classes that implement this, to pass to methods such assort()
or for use by sorting data structures such asTreeMap
andTreeSet
. 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.
- 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
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.
Related Topics
Why am I Getting Inputmismatchexception
Java Remove Duplicates from an Array
Eventlistenerlist Firing Order
Eclipse 2021-09 Code Completion Not Showing All Methods and Classes
Strange Floating-Point Behaviour in a Java Program
Javafx: Location Is Not Set Error
Rotating Coordinate Plane for Data and Text in Java
Individual and Not Continuous Jtable's Cell Selection
Java Socket Why Server Can Not Reply Client
Dealing with "Xerces Hell" in Java/Maven
What's the Difference Between Map() and Flatmap() Methods in Java 8
Which Java Collection Should I Use
Design Patterns: Factory VS Factory Method VS Abstract Factory
Eclipse/Java Code Completion Not Working
How to Get the Current Time in Yyyy-Mm-Dd Hh:Mi:Sec.Millisecond Format in Java
Differencebetween "Class.Forname()" and "Class.Forname().Newinstance()"