Link to home
Start Free TrialLog in
Avatar of gudii9
gudii9Flag for United States of America

asked on

Java Sorting: Comparator vs Comparable

Hi,

I was trying this link example to test comparator and comparable interfaces

http://www.digizol.com/2008/07/java-sorting-comparator-vs-comparable.html

When i run the TestEmployeeSort page nothing is displaying on the console. I do not see any error either. How to fix this issues.


My Employee class looks as below



public class Employee implements Comparable<Employee> { 
private int empId;
private String name;
private int age; 
public Employee(int empId, String name, int age){

}
@Override
public int compareTo(Employee o) {
// TODO Auto-generated method stub
return this.empId - o.empId ;
}
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}



EmpSortByName class looks as below




import java.util.Comparator;

public class EmpSortByName implements Comparator<Employee>{
public int compare(Employee o1, Employee o2) 
{ 
return o1.getName().compareTo(o2.getName()); 
}
} 



Util class looks as below


import java.util.*; 
public class Util { 
public static List<Employee> getEmployees() { 
List<Employee> col = new ArrayList<Employee>(); 
col.add(new Employee(5, "Frank", 28)); 
col.add(new Employee(1, "Jorge", 19));
col.add(new Employee(6, "Bill", 34));
col.add(new Employee(3, "Michel", 10)); 
col.add(new Employee(7, "Simpson", 8)); 
col.add(new Employee(4, "Clerk",16 )); 
col.add(new Employee(8, "Lee", 40));
col.add(new Employee(2, "Mark", 30)); 
return col; 
} 
} 

Test class looks as below



import java.util.Collections;
import java.util.List;

public class TestEmployeeSort {
public static void main(String[] args) { 
List coll = Util.getEmployees(); 
Collections.sort(coll); 

}
private static void printList(List<Employee> list) {
System.out.println("EmpId\tName\tAge"); 
/*for (Employee e: list) { 
System.out.println(e.getEmpId() + "\t" + e.getName() + "\t" + e.getAge()); 
} */
for (Employee e: list) { 
System.out.println(e.getEmpId() + "\t" + e.getName() + "\t" + e.getAge()); } 

Open in new window

Avatar of CPColin
CPColin
Flag of United States of America image

You're not calling printList() in Util.main(), which could explain why you see nothing in the console.
Avatar of gudii9

ASKER

You're not calling printList() in Util.main(),

Sorry i did not understand.

main is not in Util class right as below
package com.vulab.training.problem7;

import java.util.*; 
public class Util { 
	public static List<Employee> getEmployees() { 
		List<Employee> col = new ArrayList<Employee>(); 
		col.add(new Employee(5, "Frank", 28)); 
		col.add(new Employee(1, "Jorge", 19));
		col.add(new Employee(6, "Bill", 34));
		col.add(new Employee(3, "Michel", 10)); 
		col.add(new Employee(7, "Simpson", 8)); 
		col.add(new Employee(4, "Clerk",16 )); 
		col.add(new Employee(8, "Lee", 40));
		col.add(new Employee(2, "Mark", 30)); 
		return col; 
	
		} 
	
	
	
	} 

Open in new window


 printList is in TestEmployeeSort as below. What argument i supposed to pass while calling


package com.vulab.training.problem7;

import java.util.Collections;
import java.util.List;

public class TestEmployeeSort {
      public static void main(String[] args) {
            List coll = Util.getEmployees();
            Collections.sort(coll);
            
      
      }
      private static void printList(List<Employee> list) {
            System.out.println("EmpId\tName\tAge");
            /*for (Employee e: list) {
                  System.out.println(e.getEmpId() + "\t" + e.getName() + "\t" + e.getAge());
                  } */
            for (Employee e: list) {
                  System.out.println(e.getEmpId() + "\t" + e.getName() + "\t" + e.getAge()); }
                  
            }
      }
//- See more at: http://www.digizol.com/2008/07/java-sorting-comparator-vs-comparable.html#sthash.ZURRxJrl.dpuf

Please advice
printList() takes a list of employees. Pass your list of employees.
Avatar of gudii9

ASKER

I tried to pass col1 and Employee both are giving compilation erros as below. Please advice



import java.util.Collections;
import java.util.List;

public class TestEmployeeSort {
      public static void main(String[] args) {
            List coll = Util.getEmployees();
            Collections.sort(coll);
            //printList(col1);
            printList(Employee);
            
      
      }
      private static void printList(List<Employee> list) {
            System.out.println("EmpId\tName\tAge");
            /*for (Employee e: list) {
                  System.out.println(e.getEmpId() + "\t" + e.getName() + "\t" + e.getAge());
                  } */
            for (Employee e: list) {
                  System.out.println(e.getEmpId() + "\t" + e.getName() + "\t" + e.getAge()); }
                  
            }
      }
//- See more at: http://www.digizol.com/2008/07/java-sorting-comparator-vs-comparable.html#sthash.ZURRxJrl.dpuf
     public static void main(String[] args) {
            List coll = Util.getEmployees();
            Collections.sort(coll);
            //printList(col1);
            printList(Employee);
            
      
      }

Open in new window


Your variable name is coll (C-O-L-L), not col1 (C-O-L-ONE). Also, declaring coll as List<Employee> should help a bit.
Avatar of gudii9

ASKER

oh i see..

now when i run as below
import java.util.Collections;
import java.util.List;

public class TestEmployeeSort {
      public static void main(String[] args) {
            List coll = Util.getEmployees();
            Collections.sort(coll);
            printList(coll);
            //printList(Employee);
            
      
      }
      private static void printList(List<Employee> list) {
            System.out.println("EmpId\tName\tAge");
            /*for (Employee e: list) {
                  System.out.println(e.getEmpId() + "\t" + e.getName() + "\t" + e.getAge());
                  } */
            for (Employee e: list) {
                  System.out.println(e.getEmpId() + "\t" + e.getName() + "\t" + e.getAge()); }
                  
            }
      }
 i get all null and default values as below

EmpId      Name      Age
0      null      0
0      null      0
0      null      0
0      null      0
0      null      0
0      null      0
0      null      0
0      null      0



Please advice
Avatar of gudii9

ASKER

Even after adding List<Employee> also yielding same output

import java.util.Collections;
import java.util.List;

public class TestEmployeeSort {
      public static void main(String[] args) {
            List<Employee> coll = Util.getEmployees();
            Collections.sort(coll);
            printList(coll);
            //printList(Employee);
            
      
      }
      private static void printList(List<Employee> list) {
            System.out.println("EmpId\tName\tAge");
            /*for (Employee e: list) {
                  System.out.println(e.getEmpId() + "\t" + e.getName() + "\t" + e.getAge());
                  } */
            for (Employee e: list) {
                  System.out.println(e.getEmpId() + "\t" + e.getName() + "\t" + e.getAge()); }
                  
            }
      }
//-

Please advice
The constructor for your Employee class doesn't do anything, so you're not saving the values you're passing in.
Avatar of gudii9

ASKER

So the example in the link is not complete?
I just followed that link
Correct. The tutorial has this in the constructor, probably expecting you to fill in the code yourself:

// set values on attributes

Open in new window

Avatar of gudii9

ASKER

I fillled in the constructor

public Employee(int empId, String name, int age) {
            super();
            this.empId = empId;
            this.name = name;
            this.age = age;
      }

I see output as below

EmpId      Name      Age
1      Jorge      19
2      Mark      30
3      Michel      10
4      Clerk      16
5      Frank      28
6      Bill      34
7      Simpson      8
8      Lee      40


I wonder why it did not sort on the Name. please advice
You didn't tell it to:

public int compareTo(Employee o) {
// TODO Auto-generated method stub
return this.empId - o.empId ;
}

Open in new window


That only cares about the value of empId. As you can see, it did successfully sort by those values.
Avatar of gudii9

ASKER

Actually i have one the class with below compare() to sort on Name

import java.util.Comparator;

public class EmpSortByName implements Comparator<Employee>{
      public int compare(Employee o1, Employee o2)
      {
            return o1.getName().compareTo(o2.getName());
      }
      }


How do i call this and sort on Name as well
If you want a compareTo() method to look at multiple fields, the way to do it is something like this:

Compare the first pair of fields.
If that comparison returns a non-zero value, return it.
Otherwise, compare the second pair of fields and return that value instead.
Avatar of gudii9

ASKER

Actually in main method i modified code as below as mentioned in the link


public static void main(String[] args) {
            /*List<Employee> coll = Util.getEmployees();
            Collections.sort(coll);
            printList(coll);
            */
            
            List<Employee> coll = Util.getEmployees();
            //Collections.sort(coll);
            Collections.sort(coll, new EmpSortByName());
            printList(coll);                  
      
      }


To the sort method I passed additional class argument

Collections.sort(coll, new EmpSortByName());

where EmpSortByName looks like

public int compare(Employee o1, Employee o2)
      {
            return o1.getName().compareTo(o2.getName());
      }

then it sorted based on name perfect

EmpId      Name      Age
6      Bill      34
4      Clerk      16
5      Frank      28
1      Jorge      19
8      Lee      40
2      Mark      30
3      Michel      10
7      Simpson      8
Avatar of gudii9

ASKER

I wonder which of below approach they followed?

1.Compare the first pair of fields.
2.If that comparison returns a non-zero value, return it.
3.Otherwise, compare the second pair of fields and return that value instead.

when you say first pair it is id and second pair that is name right?

please advice
You've just demonstrated the difference between Comparable and Comparator!
Avatar of gudii9

ASKER

oh, What is the difference i did not notice. Please advice
If you call Collections.sort() and pass one argument, a list, it sorts the objects using the Comparable.compareTo() method that you implemented. If you call Collections.sort() and pass two arguments, a list and an instance of Comparator, it sorts the objects using the Comparator.compare() method you implemented.

That's how you got the list to sort by ID the first time, then sort by name the second time.
Avatar of gudii9

ASKER

public class Employee implements Comparable<Employee> {
      private int empId;
      private String name;
      private int age;
/*      public Employee(int empId, String name, int age){
            

}*/
      @Override
      public int compareTo(Employee o) {
            // TODO Auto-generated method stub
            return this.empId - o.empId ;
      }

I wonder for one agument as above, why the comapre() method defined in Employee class which implements Comparable interface

Whereas for two arguments why the compare() defined  in EmpSortByName  which again implements Comparator interface

public class EmpSortByName implements Comparator<Employee>{
	public int compare(Employee o1, Employee o2) 
	{ 
		return o1.getName().compareTo(o2.getName()); 
	}
	} 

Open in new window


so both Comparator and Comparable are interfaces, (none is class)?
As java cannnot support implementing multiple interfaces we have to write in separate classes
Please advise
Avatar of gudii9

ASKER

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.
- See more at: http://www.digizol.com/2008/07/java-sorting-comparator-vs-comparable.html#sthash.Q6n0sgrd.dpuf

what is meaning of comparing object itself and comparing with other object. Am i doing that here. please advice. I have not goet complete picture.
...java cannnot support implementing multiple interfaces...

Java absolutely supports implementing multiple interfaces; however, it does not support extending multiple classes.

In this case, it would not make sense for your Employee class to implement Comparable. You would have to construct an Employee instance and pass it to Collections.sort() in order to have that method sort by name instead of ID.

what is meaning of comparing object itself and comparing with other object. Am i doing that here.

Comparable.compareTo() is meant to compare this with the object that is passed in. Comparator.compare() just compares the two objects that are passed in.
Avatar of gudii9

ASKER

In this case, it would not make sense for your Employee class to implement Comparable. You would have to construct an Employee instance and pass it to Collections.sort() in order to have that method sort by name instead of ID.

I wonder why it does not make sense for Employee class to implement Comparable interface.
I told you. It's the second sentence you quoted. You would have to do this for your compare() method to be used:

Collections.sort(list, new Employee());

Open in new window


And that doesn't make much sense. Comparators should be simple and separate, for clarity.
SOLUTION
Avatar of mccarl
mccarl
Flag of Australia image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks for pointing out. I did mean Comparator.
Avatar of gudii9

ASKER

Oh Let me reread whole info and digest it
Avatar of gudii9

ASKER

Employee’s natural ordering would be done according to the employee id. - See more at: http://www.digizol.com/2008/07/java-sorting-comparator-vs-comparable.html#sthash.6LU33OVF.dpuf
what is natural ordering and why it is done according to employee id?
java.lang.Comparable: int compareTo(Object o1)
This method compares this object with o1 object. Returned int value has the following meanings.
positive – this object is greater than o1
zero – this object equals to o1
negative – this object is less than o1

java.util.Comparator: int compare(Object o1, Objecto2)
This method compares o1 and o2 objects. Returned int value has the following meanings.
positive – o1 is greater than o2
zero – o1 equals to o2
negative – o1 is less than o2
- See more at: http://www.digizol.com/2008/07/java-sorting-comparator-vs-comparable.html#sthash.6LU33OVF.dpuf

Caomparing current object with o1 object (where we are comparing two objects)is same as comparing object o1 and o2 right? how those two methods are different


java.util.Collections.sort(List) and java.util.Arrays.sort(Object[]) methods can be used to sort using natural ordering of objects.
java.util.Collections.sort(List, Comparator) and java.util.Arrays.sort(Object[], Comparator) methods can be used if a Comparator is available for comparison.
- See more at: http://www.digizol.com/2008/07/java-sorting-comparator-vs-comparable.html#sthash.6LU33OVF.dpuf

How Collections.sort, Arrays.sort are related to Compararable.compareTo() and Comparator.compare() methods?

please advice
Avatar of gudii9

ASKER

The new compareTo() method does the trick of implementing the natural ordering of the instances. So if a collection of Employee objects is sorted using Collections.sort(List) method; sorting happens according to the ordering done inside this method. - See more at: http://www.digizol.com/2008/07/java-sorting-comparator-vs-comparable.html#sthash.6LU33OVF.dpuf
Does compareTo(Employee o) internally uses sort(List)?(or may be otherway??)

Please advice
Avatar of gudii9

ASKER

Sorting by other fields

If we need to sort using other fields of the employee, we’ll have to change the Employee class’s compareTo() method to use those fields. But then we’ll loose this empId based sorting mechanism. This is not a good alternative if we need to sort using different fields at different occasions. But no need to worry; Comparator is there to save us.

By writing a class that implements the java.util.Comparator interface, you can sort Employees using any field as you wish even without touching the Employee class itself; Employee class does not need to implement java.lang.Comparable or java.util.Comparator interface. - See more at: http://www.digizol.com/2008/07/java-sorting-comparator-vs-comparable.html#sthash.6LU33OVF.dpuf
why do we loose empId based sorting mechanism if we sort using other fields of employee?
So are we saying we cannot sort using plain collection methods like sort() but to depend on comparable and comparator outside interfaces?
Please advice
why do we loose empId based sorting mechanism if we sort using other fields of employee?

If you pass a Comparator to a sort() method, the compareTo() method will be used while sorting. This means that the compare() method from Comparable will not be used.
Avatar of gudii9

ASKER

Sorting by empId field

Even the ordering by empId (previously done using Comparable) can be implemented using Comparator; following class
does that.

public class EmpSortByEmpId implements Comparator<Employee>{

public int compare(Employee o1, Employee o2) {
return o1.getEmpId() - o2.getEmpId();
}
}
- See more at: http://www.digizol.com/2008/07/java-sorting-comparator-vs-comparable.html#sthash.6LU33OVF.dpuf

when we can sort based on empID using Comparator interface itself(similar to empName) then why we need Comparable interface again separately. please advice
Avatar of gudii9

ASKER

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. Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException even though e.equals(null) returns false.

i did not get what they mentioned in documentation about natural order. why they are talking about consistency with equals here. please advice
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial