sorting - How to use Comparator in Java to sort

ID : 20219

viewed : 12

Tags : javasortingcomparatorjava

Top 5 Answer for sorting - How to use Comparator in Java to sort

vote vote

96

There are a couple of awkward things with your example class:

  • it's called People while it has a price and info (more something for objects, not people);
  • when naming a class as a plural of something, it suggests it is an abstraction of more than one thing.

Anyway, here's a demo of how to use a Comparator<T>:

public class ComparatorDemo {      public static void main(String[] args) {         List<Person> people = Arrays.asList(                 new Person("Joe", 24),                 new Person("Pete", 18),                 new Person("Chris", 21)         );         Collections.sort(people, new LexicographicComparator());         System.out.println(people);         Collections.sort(people, new AgeComparator());         System.out.println(people);     } }  class LexicographicComparator implements Comparator<Person> {     @Override     public int compare(Person a, Person b) {         return a.name.compareToIgnoreCase(b.name);     } }  class AgeComparator implements Comparator<Person> {     @Override     public int compare(Person a, Person b) {         return a.age < b.age ? -1 : a.age == b.age ? 0 : 1;     } }  class Person {      String name;     int age;      Person(String n, int a) {         name = n;         age = a;     }      @Override     public String toString() {         return String.format("{name=%s, age=%d}", name, age);     } } 

EDIT

And an equivalent Java 8 demo would look like this:

public class ComparatorDemo {      public static void main(String[] args) {         List<Person> people = Arrays.asList(                 new Person("Joe", 24),                 new Person("Pete", 18),                 new Person("Chris", 21)         );         Collections.sort(people, (a, b) -> a.name.compareToIgnoreCase(b.name));         System.out.println(people);         Collections.sort(people, (a, b) -> a.age < b.age ? -1 : a.age == b.age ? 0 : 1);         System.out.println(people);     } } 
vote vote

84

Here's a super short template to do the sorting right away :

Collections.sort(people,new Comparator<Person>(){    @Override    public int compare(final Person lhs,Person rhs) {      //TODO return 1 if rhs should be before lhs       //     return -1 if lhs should be before rhs      //     return 0 otherwise (meaning the order stays the same)      }  }); 

if it's hard to remember, try to just remember that it's similar (in terms of the sign of the number) to:

 lhs-rhs  

That's in case you want to sort in ascending order : from smallest number to largest number.

vote vote

74

Use People implements Comparable<People> instead; this defines the natural ordering for People.

A Comparator<People> can also be defined in addition, but People implements Comparator<People> is not the right way of doing things.

The two overloads for Collections.sort are different:

  • <T extends Comparable<? super T>> void sort(List<T> list)
    • Sorts Comparable objects using their natural ordering
  • <T> void sort(List<T> list, Comparator<? super T> c)
    • Sorts whatever using a compatible Comparator

You're confusing the two by trying to sort a Comparator (which is again why it doesn't make sense that Person implements Comparator<Person>). Again, to use Collections.sort, you need one of these to be true:

  • The type must be Comparable (use the 1-arg sort)
  • A Comparator for the type must be provided (use the 2-args sort)

Related questions


Also, do not use raw types in new code. Raw types are unsafe, and it's provided only for compatibility.

That is, instead of this:

ArrayList peps = new ArrayList(); // BAD!!! No generic safety! 

you should've used the typesafe generic declaration like this:

List<People> peps = new ArrayList<People>(); // GOOD!!! 

You will then find that your code doesn't even compile!! That would be a good thing, because there IS something wrong with the code (Person does not implements Comparable<Person>), but because you used raw type, the compiler didn't check for this, and instead you get a ClassCastException at run-time!!!

This should convince you to always use typesafe generic types in new code. Always.

See also

vote vote

66

For the sake of completeness, here's a simple one-liner compare method:

Collections.sort(people, new Comparator<Person>() {     @Override     public int compare(Person lhs, Person rhs) {           return Integer.signum(lhs.getId() - rhs.getId());       } }); 
vote vote

55

Java 8 added a new way of making Comparators that reduces the amount of code you have to write, Comparator.comparing. Also check out Comparator.reversed

Here's a sample

import org.junit.Test;  import java.util.ArrayList; import java.util.Comparator; import java.util.List;  import static org.junit.Assert.assertTrue;  public class ComparatorTest {      @Test     public void test() {         List<Person> peopleList = new ArrayList<>();         peopleList.add(new Person("A", 1000));         peopleList.add(new Person("B", 1));         peopleList.add(new Person("C", 50));         peopleList.add(new Person("Z", 500));         //sort by name, ascending         peopleList.sort(Comparator.comparing(Person::getName));         assertTrue(peopleList.get(0).getName().equals("A"));         assertTrue(peopleList.get(peopleList.size() - 1).getName().equals("Z"));         //sort by name, descending         peopleList.sort(Comparator.comparing(Person::getName).reversed());         assertTrue(peopleList.get(0).getName().equals("Z"));         assertTrue(peopleList.get(peopleList.size() - 1).getName().equals("A"));         //sort by age, ascending         peopleList.sort(Comparator.comparing(Person::getAge));         assertTrue(peopleList.get(0).getAge() == 1);         assertTrue(peopleList.get(peopleList.size() - 1).getAge() == 1000);         //sort by age, descending         peopleList.sort(Comparator.comparing(Person::getAge).reversed());         assertTrue(peopleList.get(0).getAge() == 1000);         assertTrue(peopleList.get(peopleList.size() - 1).getAge() == 1);     }      class Person {          String name;         int age;          Person(String n, int a) {             name = n;             age = a;         }          public String getName() {             return name;         }          public int getAge() {             return age;         }          public void setName(String name) {             this.name = name;         }          public void setAge(int age) {             this.age = age;         }     }    } 

Top 3 video Explaining sorting - How to use Comparator in Java to sort

Related QUESTION?