In my taks I need to sort names with lambda. Class lambdaComparator extends class Car.
I make class LambdaComparator like this:
public class LambdaComparator extends Car
public LambdaComparator(String name) {super(name);}
In this class I need to sort objects of type Car.
In main class I have list of objects and with function I need to sort it.
In class LambdaComparator I have this:
Collections.sort(list, new Comparator<Car>() {
public int compare(Car x, Car y) {
return x.getName().compareTo(y.getName()));
}
});
How should I call function in main to get this sorted, should I make function of type void in class to somehow call it.
Edit: lambda expression
class LambdaSort<T extends Car>
private List<T> listOfCars;
public LambdaComparator(){
this.listOfCars = new ArrayList<T>();
}
public void sortCars(T cars)
listOfCars.sort((Car o1, Car o2)->o1.getName().compareTo(o2.getName());
In main function I add objects of type car to that list.
A lambda comparator would be something like this.
Comparator<Car> comp = (c1, c2)-> c1.getName().compareTo(c2.getName());
In the above example, the Comparator is comparing on a specific field of the Car class, name. Since name probably returns a string, one can use compareTo since the String class implements the Comparable (not Comparator) interface for comparing Strings.
But the lambda could be specified much more easily using one of the methods in the Comparator interface. The comparing method may take a lambda or a method reference (shown below).
Comparator<Car> comp = Comparator.comparing(Car::getName);
Then when it is passed to the sort method, the sort method will apply it to the objects under sort as comp.compare(obj1, obj2) (although it may not be called comp in the method that uses it)
For more information, check out The Java Tutorials
Take a look at what lambda is here.
If you have a list in your main class, it's as simple as just sorting it. You probably don't even need the class LambdaComparator.
List<Car> list = new ArrayList<>();
Collections.sort(list, (a, b) -> a.getName().compareTo(b.getName()));
I've seen a few questions about the sort for collections having errors in Java. The error I am showing is this:
The method sort(List<T>) in the type Collections is not applicable for the arguments (ArrayList<Time>)
I have imported java.util.Collections and ArrayList. I also imported the class I am calling from. Here is my code:
In the class being called from:
private ArrayList<Time> times;
...
public ArrayList<Time> getTimes() {
return this.times;
}
In the class I am calling the array list to:
public class TimeTUI {
private Scanner scan;
private TimeManager timeManager;
...
private ArrayList<Time> getSortedTimes() {
ArrayList<Time> sortedTimes = this.timeManager.getTimes();
Collections.sort(sortedTimes);
return sortedTimes;
}
The error is appearing on the line showing:
Collections.sort(sortedTimes);
The class Time has to be a Comparable.
Collections.sort(List) expects that the class T implements Comparable interface. If you have used many of the inbuilt classes, you wouldn't find problem, but for the custom classes sort doesn't know how to sort them. So, by implementing Comparable interface, you give definition to a method compareTo.
public class Time implements Comparable {
public int compareTo(Object o) {
// provide your logic of how to sort Time objects.
}
}
Your class type in the List or ArrayList must implement the Interface comparable and override properly the compareTo(...) method,
Is you break this contract and dont implement the interface. the Class Collections has not a valid criteria/rule to compare/sort your list, and therefore your compiler will complain...
I don't think that it is the ArrayList that is the issue here. For example:
ArrayList<String> names = new ArrayList<>();
...
Collections.sort(names);
works just fine.
The content of the list must be comparable so that the sort can work. In this case the Time class and any sub-type must implement Comparable.
"How will you sort collection of employee objects by its id or name". For that we can use two interfaces, i.e., Comparator and Comparable.
seems this is one of the common interview questions
But I don't see a reason why I should use both for sorting employee objects
I have been thinking on what comparator accomplishes that Comparable cannot do.
I understand that if the objects (instance variables that is compared upon) have natural ordering then comparable is the right choice.
but if custom ordering is needed (eg string length) then one could write a comparator.
my point here is comparator is only needed by the client if he wants to sort the data by some other criteria.
For example, I would implement an Employee class to sort by id using comparable interface.
but if the client wants to sort Employee objects by String(name), he would implement comparator either as a concrete class or anonymously in sorting.
Is there anything I am missing here?
For example, In the following code, for the Person object, my compareTo method, compares the age and sort it
In the compare method, I use String length (name of the person) for sorting. In theory, I could accomplish both in the compareTo method as I have implemented below.
lastly, are there any added benefits of one of the following over other
I have implemented comparator in two ways
1. as a static method which is commented out
2. as anonymous object(?) in the main method which is commented out
3. make a new class that implements comparator and call the instance of that class in collections.sort() -- this I have not done here
(The commented-out parts of the code works. They are just different implementations)
mport java.util.Collections;
import java.util.Comparator;
import java.util.*;
public class PersonComparator implements Comparable{
private String name;
private int age;
public PersonComparator(String name, int age) {
this.name = name;
this.age = age;
}
#Override
public String toString() {
return "name=" + name + ", age=" + age;
}
/*#Override
public int compareTo(Object obj) {
if (!(obj instanceof PersonComparator)) {
throw new ClassCastException("Invalid object");
}
PersonComparator p2 = (PersonComparator)obj;
return this.age-p2.age;
}*/
/*Alternative CompareTo that checks for both age and name*/
public int compareTo(Object obj) {
if (!(obj instanceof PersonComparator)) {
throw new ClassCastException("Invalid object");
}
PersonComparator p2 = (PersonComparator)obj;
if (this.age!=p2.age){
return this.age-p2.age;
}
else {
return (this.name.length()-p2.name.length());
}
}
/*public static Comparator nameLengthComparator
= new Comparator() {
#Override
public int compare(Object obj1, Object obj2) {
if (!(obj1 instanceof PersonComparator) || !(obj2 instanceof PersonComparator)){
throw new ClassCastException("Invalid object");
}
else {
PersonComparator p1 = (PersonComparator)obj1;
PersonComparator p2 = (PersonComparator)obj2;
return p1.name.length()-p2.name.length();
}
}
};*/
public static void main(String[] args){
PersonComparator p1 = new PersonComparator("Alexander", 45);
PersonComparator p2 = new PersonComparator("Pat", 27);
PersonComparator p3 = new PersonComparator("Zacky", 45);
PersonComparator p4 = new PersonComparator("Rake", 34);
List<PersonComparator> list = new ArrayList<PersonComparator>();
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);
System.out.println("Before sorting "+ list);
Collections.sort(list);
//System.out.println("After sorting by age "+ list);
//System.out.println("Before sorting "+ list);
//Collections.sort(list, nameLengthComparator);
System.out.println("After sorting by name length "+ list);
/*Collections.sort(list, new Comparator<PersonComparator>() {
#Override
public int compare(PersonComparator p1, PersonComparator p2) {
return p1.name.length()-p2.name.length();
}
}
);*/
System.out.println("After sorting by name length "+ list);
}
}
Thanks
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.
In what way is a comparator superior to comparable?
It is not "superior". It is just that the two interfaces are doing (roughly) the same thing in different ways. In the Comparable case the ordering logic is in the object being ordered. In the Comparator case, the logic is in a different class from the objects being declared.
But I don't see a reason why I should use both for sorting employee objects
The only case where it would make sense to use both would be if you needed to be able to sort the objects into different orders. Then you could declare the relevant classes as implementing Comparable for the "natural" order and use Comparator objects to implement the other orders.
By the way, a comparator probably should not implement Comparable, and vice versa.
If a comparator implements Comparable that implies you are trying to order instances of the comparator object itself ...
Your PersonComparator class is misnamed. It should really be called Person.
Could you clarify one thing in your answer that we have already equals() method from Object class then why the Comparator interface is facilitating the equals() method again?
A number of points:
You still seem to be confusing the purpose of Comparable and Comparator. The equals method on a Comparator object compares the comparator with other comparators!!
The equals method tells you whether two objects are equal ... not which one comes first.
The reason that Comparator overrides equals is solely so that they can clearly document what equals(Object) does when you call it on a Comparator object. (The actual behaviour is entirely consistent with Object.equals(Object) ... but they obviously thought it necessary to do this because programmers were repeatedly getting the semantics of the method wrong.)
In what way is a comparator superior to comparable?
I won't say it is superior but one advantage is that it enables us to write multiple sort sequences. In case of Comparable, you would have to implement that interface by your class which you want to sort and you can write only one sort sequence.
With Comparator, you can make different classes for sort sequences and while sorting, you just pass the Comparator instance to COllections.sort() method.
Consider Employee class which has fields id, firstName and lastName. If you implement Comparable, you can write only one sorting logic in compareTo method.
If you implement Comparator then you can create separate sorting sequences by creating separate classes. e.g. IdSorter, FirstNameSorter and LastNameSorter which gives you way to sort Employee in multiple ways.
Read
Sorting user defined objects with Comparator
Comparable allows you to sort items in a collections based on only one field.Comparator provides the flexibility to compare items based on more than one field
For example.
class Person implements Comparable
{
int age;
String name;
Person(int age,String name)
{
this.age=age;
this.name=name;
}
public int compareTo(Object o1) // Either you can compare according to age or name
{
Person p = (Person)o1;
if (this.age==p.age)
return 0;
else if (this.age>p.age)
return 1;
else
return -1;
}
public int compareTo(Object o) //Based on name comparision
{
return (this.name.compareTo((Person)o).name));
}
public static void main (String args[])
{
List<Person> list = new ArrayList<Person>();
Person o = new Person(12,"Steve");
Person o1 = new Person(13,"Jason");
list.add(o);
list.add(o1);
Collections.sort(list);
}
}
In case of Comparable above, you can sort items either using age or name.But in case of Comparator ,you can sort the items based on more than one field.
class AgeComparison implements Comparator
{
public int compare(Object o1,Object o2)
{
Person s1 = (Person)o1;
Person s2 =(Person)o2;
if (s1.age==s2.age)
return 0;
if(s1.age>s2.age)
return 1;
else
return -1;
}
class NameComparison implements Comparator
{
public int compare(Object o1,Object o2)
{
Person s1 = (Person)o1;
Person s2 =(Person)o2;
return (s1.age.compareTo(s2.age));
}
}
To use Comparator, you have to pass the list and the instance of class you have to use.
Collections.sort(list,new NameComparison());
Collections.sort(list,new AgeComparison());
In a nutshell, the advantage of Comparator is the flexibility to sort the list based on more than one field of the object.
In general, use Comparable when the ordering is "obvious". E.g., for Strings you use alphabetical, for numbers you use numeric order. Note that a Comparable object can only implement a single compareTo() method, so you only get one option - the "natural", "obvious" option. The advantage is that it is simple and client code doesn't have to do any extra work to compare things.
Use Comparator if the ordering is less obvious, or you might want to have multiple options. For example, a Book might get sorted by Title, Author, ISBN, etc. You could have three different Comparators to handle those three cases. You might want to sort Strings by some unusual order, e.g. a special case for a foreign language, ignoring capitals, etc.
Also, if the Objects you are sorting do not implement Comparable, or you are mixing types that do not like to compare to each other (in general, this is to be avoided, but perhaps you want to be able to compare Books and Authors in a single list in some special case) you need to use Comparator.
Here you go... I have already written a lot on this clarification aided with pictures and explanations.
Please find the link below:
Comparable and Comparator
One think you can always remember and that is "they can’t be used interchangeably"
If you are using comparator , you just need to add one comparator class and pass it to Collections.sort() method along with List object no other change in existing code.
but if you implement comparable interface you will have to change code of all the model/bean classes to override compareTo() method.
so for Loose Coupling comparator is better.
I have a list of DataPoint objects. The class definition is:
public static class DataPoint
{
public Comparable X;
public Comparable Y;
public Comparable Z;
public String text;
...
}
"list" is an ArrayList of DataPoint objects. How do I sort list only on the X value? Would Collections.sort(list, comparator) be used here?
Yes, you should create specific comparator for each field. Example:
Comparator<DataPoint> compByX = new Comparator<DataPoint>() {
#Override
public int compare(DataPoint left, DataPoint right) {
return left.X.compareTo(right.X);
}
};
Collections.sort(list, compByX);
You have two choices:
implement Comparable<DataPoint> for your DataPoint class
write a custom comparator that implements Comparator<DataPoint> and then use Collections.sort
First solution is meaningful if you want to give a natural ordering on your objects (which will be the most used one). Usually it's the one you use first while you use comparators just when you need additional orderings.
They both behave in the same way but Comparable<T> is inherently attached to the object as it is its default comparison algorithm. Whenever sorting is involved the default one will be used unless you specify another one.
class DataPoint implements Comparable<DataPoint> {
#Override
public int compareTo(DataPoint o) {
return X.compareTo(o.X);
}
}
Mind that when you need to compare objects you usually need also other operations on them so take care of overriding hashCode() and equals(Object o). The latter is used in sorting as documentations states:
The natural ordering for a class C is said to be consistent with equals if and only if e1.compareTo(e2) == 0 has the same boolean value as e1.equals(e2) for every e1 and e2 of class C. ... It is strongly recommended (though not required) that natural orderings be consistent with equals.
This means that if you just compare X variable then two different DataPoint objects with same X will be considered equal with respect to compareTo. This can lead to strange situations.
I'm trying to sort a Vector in java but my Vector is not a vector of int, it is a vector of objects
the object is:
public MyObject() {
numObj = 0;
price = new Price();
pax = new Pax();
}
so I have a Vector of MyObject and I want to order it by numObject, how do i do it, I'm new in java?
Thank you so much for all your help.
I assume you are using Collections.sort(..). You have two options:
make your class implement Comparable
when sorting, create a custom Comparator
An example for implementing Comparable would be:
public class MyObject implements Comparable<MyObject> {
// ..... other fields and methods
public int compareTo(MyObject other) {
return numObj - other.getNumObj();
}
}
This will mean the items are sorted in ascending order. If you want other, custom sorting, you can create a Comparator that defines the custom comparison and pass it as an argument to Collections.sort(..);
To sort a vector of object, first the class MyObject must implement Comparable and implement method compareTo(Object), then use Collections.sort(Vector)
class MyObject implements Comparable<MyObject> {
public int compareTo(MyObject a) {
//return either 1, 0, or -1
//that you compare between this object and object a
``}
}
//and in your logic write this line
Collections.sort(myVector);
check the JavaDoc of Vector
Implementing Comparable will work fine. However, it should be done with caution in order to prevent future bugs. The implementations above are great for sorting, but if you later decide to put your MyObject instances into a SortedSet (such as TreeSet), you will have an unexpected behavior. Items which are not identical will collide with each other if they have the same value of the numObject data member. This happens because sorted sets use the Comparable implementation (by default) in order to determine equality.
See http://eyalsch.wordpress.com/2009/11/23/comparators/ for details.