Sunday, November 8, 2015

Collections class sort method (Comparator for nulls)

Collections class sort method (Comparator for nulls)

In previous two posts we saw how to use Comparable interface in Collections.sort(List<T>) and how to use Comparator interface in Collections.sort(List<T> list, Comparator<? super T> c).

Both the previous post has one problem in common. If there is/are null elements in List<T> then Collections.sort(..) will throw NullPointerException.

So in this post we will see how to write a Comparator that will skip the null elements and Compare only the actual elements (elements that are not null).

Following is one way to write conditions in a comparator.

1.    If first object is null and second object is null then return 0. Because if both are null means both are same.
2.    If first object is null and second object is not null return -1. This step assumes that elements that are null are smaller than elements that are not null. (If you return 1 then all null elements will be at the end of List).
3.    If first object is not null and second object is null return 1. Because first object contains value and second object is null. This step is reverse of Step 2.
4.    If both the objects contains value then return object1.compareTo(object2).

Below is the code for the Collections.sort with Comparator.

public void sortForNulls(final List<String> names) {
      Collections.sort(names, new Comparator<String>() {
            @Override
            public int compare(final String name1,
                               final String name2) {

                  if (name1 == null) {
                        if (name2 == null) {
                              //Step 1
                              return 0;
                        }
                        //Step 2
                        return -1;
                  } else if (name2 == null) {
                        //Step 3
                        return 1;
                  }
                  //Step 4
                  return name1.compareTo(name2);
            }
      });
}
Watch out the comments that are written. It describes the 4 different scenarios.

Let us write entire code with

public class ListSortComparator {

      public static void main(String[] args) {
            ListSortComparator lsc = new ListSortComparator();
            List<String> names = lsc.names();
            lsc.sortForNulls(names);
            System.out.println(names);
      }

      public List<String> names() {
            List<String> names = new ArrayList<String>();
            names.add("Sansa");
            names.add("Ramsay");
            names.add("Eddard");
            names.add("Benjen");
            names.add("Robb");
            names.add("Catelyn");
            names.add(null);
            names.add("Rickon");
            names.add(null);
            names.add("Brandon");
            return names;
      }

public void sortForNulls(final List<String> names) {
            Collections.sort(names, new Comparator<String>() {
                  @Override
                  public int compare(final String name1,
                                     final String name2) {

                        if (name1 == null) {
                              if (name2 == null) {
                                    //Step 1
                                    return 0;
                              }
                              //Step 2
                              return -1;
                        } else if (name2 == null) {
                              //Step 3
                              return 1;
                        }
                        //Step 4
                        return name1.compareTo(name2);
                  }
            });
      }
}

Output:
Before Sort: [Sansa, Ramsay, Eddard, Benjen, Robb, Catelyn, null, Rickon, null, Brandon]

After Sort:  [null, null, Benjen, Brandon, Catelyn, Eddard, Ramsay, Rickon, Robb, Sansa]



Collections class sort(List, Comparator) method

Collections class sort(List, Comparator) method

In previous post we saw sort method that accepts List as argument. We sorted the List<String> where String class implements the Comparable<T> interface. We also saw the example of Person class and implemented the Comparable<T> interface and sorted the List.

In this post we will see how to implement the Comparator interface. You can read about Comparator interface here.

Let us take a Person class which will have two attributes namely age and name. We will write Comparator for age and name and sort the list.

Below is the Person class.

public class People {

      private int age;
      private String name;

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

      public int getAge() {
            return age;
      }

      public void setAge(int age) {
            this.age = age;
      }

      public String getName() {
            return name;
      }

      public void setName(String name) {
            this.name = name;
      }
     
      @Override
      public String toString() {
            return new StringBuilder()
                              .append("{")
                              .append(this.getName())
                              .append(" ")
                              .append(this.getAge())
                              .append("}")
                              .toString();
      }

}

Below is the class the uses the Comparator<T> to sort List<People> by age and name.


import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class ComparatorDemo {

      public static void main(String[] args) {

            List<People> list = new ArrayList<People>();
            list.add(new People("Eddard", 55));
            list.add(new People("Rob", 23));
            list.add(new People("Joffery", 21));
            list.add(new People("Sansa", 19));
            list.add(new People("Rickon", 7));
            list.add(new People("Brandon", 9));
            System.out.println("Before Sort     " + list);
            sortByName(list);
            sortByAge(list);
      }

      /**
       * Below method sorts the List<People> using the
       * Comparator as Anonymous Inner Class.
       * */
      public static void sortByName(List<People> list) {
            Collections.sort(list, new Comparator<People>() {
                  public int compare(People p1, People p2) {
                        return p1.getName().compareTo(p2.getName());
                  }
            });
            System.out.println("Sorted by Name: " + list);
      }

      /**
       * Below method sorts the List<People> using the
       * Comparator as Anonymous Inner Class.
       * */
      public static void sortByAge(List<People> list) {
            Collections.sort(list, new Comparator<People>() {
                  public int compare(People p1, People p2) {
                        if (p1.getAge() == p2.getAge()) {
                              return 0;
                        } else if (p1.getAge() < p2.getAge()) {
                              return -1;
                        } else {
                              return 1;
                        }
                  }
            });
            System.out.println("Sorted by Age:  " + list);
      }
}

Output

Before Sort     [{Eddard 55},
     {Rob 23},
     {Joffery 21},
     {Sansa 19},
     {Rickon 7},
     {Brandon 9}]

Sorted by Name: [{Brandon 9},
     {Eddard 55},
     {Joffery 21},
     {Rickon 7},
     {Rob 23},
     {Sansa 19}]

Sorted by Age:  [{Rickon 7},
     {Brandon 9},
     {Sansa 19},
     {Joffery 21},
     {Rob 23},
     {Eddard 55}]


 That’s all on Collections.sort(List, Comparator) method. In next post we will see how to use Comparator interface to sort the List which contains null elements. 

Saturday, November 7, 2015

Collections class sort method

Collections class sort method.

sort() method is used to sort List of elements. sort() method is overloaded method. Below are the two overloaded sort() methods:
1.      sort(List<T> list)
2.    sort(List<T> list, Comparator<? super T> c)

In this post we will see both the versions of sort() method.

First we will see the sort(List<T> list). This method accepts the List<T>. It sorts the list in ascending order according to Comparable interface’s natural ordering of elements.  All elements in list must implement Comparable and they must be mutually comparable that is o1.compareTo(o2) must not throw ClassCastException.

Below is the demo code for Collections.sort(list) method.

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

public class ListSort {

      public static void main(String[] args) {
            ListSort lsc = new ListSort();
            List<String> names = lsc.names();
            lsc.sortList(names);
      }
     
      public List<String> names() {
            List<String> names = new ArrayList<String>();
            names.add("Sansa");
            names.add("Ramsay");
            names.add("Eddard");
            names.add("Benjen");
            names.add("Robb");
            names.add("Catelyn");
            names.add("Rickon");
            names.add("Brandon");
            return names;
      }

      public void sortList(final List<String> names) {
            System.out.println("Before Sort: "+names);
            Collections.sort(names);
            System.out.println("After Sort:  "+names);
      }
}

Output:
Before Sort: [Sansa, Ramsay, Eddard, Benjen, Robb, Catelyn, Rickon, Brandon]
After Sort:  [Benjen, Brandon, Catelyn, Eddard, Ramsay, Rickon, Robb, Sansa]

If the see the output it is sorted lexical order or alphabetical order. Remember String class implements the Comparable<T> interface so the sorting takes place.

Now let implement the Comparable interface in Person class and sort it.

Below is the Person class that implements the Comparable<T> interface.


public class Person implements Comparable<Person>{

      private int age;
      private String name;

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

      public int getAge() {
            return age;
      }

      public void setAge(int age) {
            this.age = age;
      }

      public String getName() {
            return name;
      }

      public void setName(String name) {
            this.name = name;
      }

      /**
       * compareTo(T o) is used as natural comparison method where
       * comparison is done on lexical order on Person's name.
       * */
      @Override
      public int compareTo(Person person) {
            return this.getName().compareTo(person.getName());
      }
     
      @Override
      public String toString() {
            return new StringBuilder()
                              .append("{")
                              .append(this.getName())
                              .append(" ")
                              .append(this.getAge())
                              .append("}")
                              .toString();
      }

}

Below is Driver class that builts a list and sorts it.

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

public class PersonComparable {

      public static List<Person> personList() {
            List<Person> list = new ArrayList<Person>();
            list.add(new Person("Eddard", 55));
            list.add(new Person("Rob", 23));
            list.add(new Person("Joffery", 21));
            list.add(new Person("Sansa", 19));
            list.add(new Person("Rickon", 7));
            list.add(new Person("Brandon", 9));
            return list;
      }

      public static void main(String[] args) {
            List<Person> people = personList();
            System.out.println(people);
            Collections.sort(people);
            System.out.println(people);
      }
}

Output:
Before sort: [{Eddard 55},
 {Rob 23},
 {Joffery 21},
 {Sansa 19},
 {Rickon 7},
 {Brandon 9}]

After sort:  [{Brandon 9},
 {Eddard 55},
 {Joffery 21},
 {Rickon 7},
 {Rob 23},
 {Sansa 19}]

That’s all on Collections.sort(list). In next post we will see how to implement Comparator<T> for sorting the objects using different ordering.


Notice if there is null in List<T> then Collections.sort(list) will throw NullPointerException. So this is unsafe practice. We can write our own Comparator to avoid NullPointerException. 

Ads Inside Post