Java Sorting Example(Comparable and Comparator)

Java Sorting Example(Comparable and Comparator)

In this article, we will cover Java Sorting Example (Comparable and Comparator). Java Collection API provides a way to sort Array and Lists but it expects input from the developer. This article will try to give an example to use both java.lang.Comparable and java.util.Comparator to sort objects.

 

1. Sort an ArrayList

Collections API’s utility class Collections provide a handy way to sort an ArrayList in a natural ordering provided all elements in the list must implement the Comparable interface.

public class SimpleSorting {

    public static void main(String[] args) {

        List<String> locationList = new ArrayList<String>();
        locationList.add("California");
        locationList.add("Texas");
        locationList.add("Seattle");
        locationList.add("New Delhi");

        Collections.sort(locationList);

        for (String location : locationList) {
            System.out.println("Location is: " + location);
        }
    }
}

Output

Location is: California
Location is: New Delhi
Location is: Seattle
Location is: Texas

Above example worked perfectly with Collections.Sort() as List defined in example was Lits<String> and java.lang.String implements the Comparable interface. With List contains custom objects, Collections.sort() will fail if the custom object does not implement the Comparable interface.

 

2. Sort Object using Comparable

public class Person implements Comparable<Person> {

    private String name;
    private int age;

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

    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;
    }

    public int compareTo(Person person) {
        return this.age > person.age ? 1 : this.age < person.age ? -1 : 0;
    }
}

To sort it, we will use Collections.sort() method

public class ComparableDemo {

    public static void main(String[] args) {

        List<Person> persons = new ArrayList<Person>();

        persons.add(new Person("Umesh Awasthi", 35));
        persons.add(new Person("Robert Hickle", 55));
        persons.add(new Person("John Smith", 40));
        persons.add(new Person("David", 23));

        Collections.sort(persons);

        for (Person person : persons) {
            System.out.println("Person is: " + person.getName());
        }

    }
}

Output is

Person is: David
Person is: Umesh Awasthi
Person is: John Smith
Person is: Robert Hickle

Pay close attention to Person class declaration public class Person implements Comparable<Person>  which shows that Person class is a comparable if you remove Comparable<Person> from your Person class and try Collection.sort(persons) , compile will give the following error

Error:(21, 20) java: no suitable method found for sort(java.util.List<com.umeshawasthi.tutorials.corejava.sorting.Person>)
    method java.util.Collections.<T>sort(java.util.List<T>) is not applicable
      (inferred type does not conform to upper bound(s)
        inferred: com.umeshawasthi.tutorials.corejava.sorting.Person
        upper bound(s): java.lang.Comparable<? super com.umeshawasthi.tutorials.corejava.sorting.Person>)
    method java.util.Collections.<T>sort(java.util.List<T>,java.util.Comparator<? super T>) is not applicable
      (cannot infer type-variable(s) T
        (actual and formal argument lists differ in length))

As a developer, it’s out responsibility to pass the comparable object to Collections.sort() method.

It’s up to you how you want to use the compareTo method and what will be your comparison logic, I have used a simple logic to compare the age of the person but you can use any custom logic to in compareTo()  method.

 

3. Sort Object using Comparator

java.lang.Comparable interface provides only one way to compare this object with another one, what are the options in case we need to compare 2 objects to sort them correctly. How about sorting Person with a name or age?  What if we want to override the natural ordering? We need to create a Comparator for these requirements.

First and super short template is to provide a custom comparator while calling Collections.sort()  method

public class ComparatorDemo {

    public static void main(String[] args) {
        List<Person> persons = new ArrayList<Person>();

        persons.add(new Person("Umesh Awasthi", 35));
        persons.add(new Person("Robert Hickle", 55));
        persons.add(new Person("John Smith", 40));
        persons.add(new Person("David", 23));
        persons.add(new Person("David", 63));

        Collections.sort(persons, new Comparator<Person>() {
            public int compare(Person person, Person person1) {
                int name = person.getName().compareTo(person1.getName());
                if(name == 0){
                    return name;
                }
                return person.getAge() > person1.getAge() ? 1 : person.getAge() < person1.getAge() ? -1 : 0;
            }
        });


        for (Person person : persons) {
            System.out.println("Person is: " + person.getName());
        }
    }
}

Output

Person is: David
Person is: Umesh Awasthi
Person is: John Smith
Person is: Robert Hickle
Person is: David

Check the output, the interesting part is David, which is first and last result of the output.Another efficient way is to define the Comparators in the Contact itself to reuse them instead of recreating every time

public class ComparatorPerson {

    private String name;
    private int age;

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

    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;
    }

    public static Comparator<ComparatorPerson> COMPARE_BY_NAME = new Comparator<ComparatorPerson>() {
        public int compare(ComparatorPerson one, ComparatorPerson other) {
            return one.name.compareTo(other.name);
        }
    };

    public static Comparator<ComparatorPerson> COMPARE_BY_AGE = new Comparator<ComparatorPerson>() {
        public int compare(ComparatorPerson one, ComparatorPerson other) {
            return one.age > other.age ? 1 : one.age < other.age ? -1 : 0;
        }
    };
}

Comparator with multi options

public class MultiComparatorDemo {
    public static void main(String[] args) {
        List<ComparatorPerson> persons = new ArrayList<ComparatorPerson>();

        persons.add(new ComparatorPerson("Umesh Awasthi", 35));
        persons.add(new ComparatorPerson("Robert Hickle", 55));
        persons.add(new ComparatorPerson("John Smith", 40));
        persons.add(new ComparatorPerson("David", 23));
        persons.add(new ComparatorPerson("David", 63));

        Collections.sort(persons,ComparatorPerson.COMPARE_BY_AGE );

        for (ComparatorPerson person : persons) {
            System.out.println("Person Name Sorted by Age is: " + person.getName());
        }

        System.out.println("######################################################");
        Collections.sort(persons,ComparatorPerson.COMPARE_BY_NAME );

        for (ComparatorPerson person : persons) {
            System.out.println("Person Name Sorted by Name  is: " + person.getName());
        }
    }
}

Output

Person Name Sorted by Age is: David
Person Name Sorted by Age is: Umesh Awasthi
Person Name Sorted by Age is: John Smith
Person Name Sorted by Age is: Robert Hickle
Person Name Sorted by Age is: David
######################################################
Person Name Sorted by Name  is: David
Person Name Sorted by Name  is: David
Person Name Sorted by Name  is: John Smith
Person Name Sorted by Name  is: Robert Hickle
Person Name Sorted by Name  is: Umesh Awasthi

 

4. Sort Object using Java8

Java 8 added a new way of making Comparators that reduces the amount of code you have to write Comparator.comparing. Java 8 streaming API provides neater approach. It’s always good to understand how compareTo()  and compare()  method work under the hood

public class Java8CompareExample {

    public static void main(String[] args) {

        List<Person> persons = new ArrayList<Person>();

        persons.add(new Person("Umesh Awasthi", 35));
        persons.add(new Person("Robert Hickle", 55));
        persons.add(new Person("John Smith", 40));
        persons.add(new Person("David", 23));
        persons.add(new Person("David", 63));

        persons.sort(Comparator.comparing(Person::getName).thenComparingInt(Person::getAge));

        for (Person person : persons) {
            System.out.println("Person Name is: " + person.getName());
        }

        persons.sort(Comparator.comparingInt(Person::getAge).thenComparing(Person::getName));

        for (Person person : persons) {
            System.out.println("Person Name is: " + person.getName());
        }
    }
}

In this article, we cover Java Sorting Example (Comparable and Comparator) provided by JDK, we will cover other API which provides the same functionalities with additional features. All the code of this article is available Over on Github. This is a Maven-based project. As a bonus, have a look at Apache Common ComparatorUtils which provide some ready to use a feature for you.

Reference

  1. Comparator
  2. Comparable
  3. Comparator.comparing