ArrayList is one of the most commonly used collection classes of the Java Collection Framework because of the functionality and flexibility it provides. ArrayList is a List implementation that internally implements a dynamic array to store elements. Therefore, an ArrayList can dynamically grow and shrink as you add and remove elements to and from it. It is likely that you have used ArrayList, therefore I will skip the basics. If you are not familiar with ArrayList yet, you can go through its API documentation here, which is very descriptive and easy to understand to perform basic operations on ArrayList.

In this post, I will discuss one of the most important operation on ArrayList that you will most likely require implementing during enterprise application development. It’s sorting the elements of an ArrayList.

Sorting an ArrayList of String Objects

Consider an ArrayList that stores country names as String objects. To sort the ArrayList, you need to simply call the Collections.sort() method passing the ArrayList object populated with country names. This method will sort the elements (country names) of the ArrayList using natural ordering (alphabetically in ascending order). Lets’s write some code for it.

SortArrayListAscendingDescending.java

In the class above, we initialized an ArrayList object in the constructor. In the sortAscending() method, we called the Collections.sort() method passing the initialized ArrayList object and returned the sorted ArrayList. In the sortDescending() method we called the overloaded Collections.sort() method to sort the elements in descending order. This version of Collections.sort() accepts the ArrayList object as the first parameter and a Comparator object that the Collections.reverseOrder() method returns as the second parameter. We will come to Comparator a bit later. To test the sorting functionality, we will write some test code.

SortArrayListAscendingDescendingTest.java

In the test code above, we created a ArrayList object and added five String objects that represent the names of five countries to it. We then called the getArrayList(), sortAscending(), and sortDescending() methods and printed out the ArrayList objects that the methods return.

The output is this.

At this point, it might appear that sorting elements of an ArrayList is very simple. We only need to call the Collections.sort() method passing the ArrayList object whose elements needs to be sorted. But, there is more to sorting ArrayLists as you encounter additional scenarios.

The Collections.sort() method sorts ArrayList elements or elements of any other List implementation provided the elements are comparable. What this means programmatically is that the classes of the elements need to implement the Comparable interface of the java.lang package. As the String class implements the Comparable interface, we were able to sort the ArrayList of country names. Some other classes standard to Java which implement the Comparable interface include the primitive wrapper classes, such as Integer, Short, Double, Float, and Boolean. BigInteger, BigDecimal, File, and Date are also examples of classes that implement Comparable.

Sorting an ArrayList using Comparable

Comparable is an interface with a single compareTo() method. An object of a class implementing Comparable is capable of comparing itself with another object of the same type. The class implementing Comparable needs to override the compareTo() method. This method accepts an object of the same type and implements the logic for comparing this object with the one passed to compareTo(). The compareTo() method returns the comparison result as an integer that has the following meanings:

  • A positive value indicates that this object is greater than the object passed to compareTo().
  • A negative value indicates that this object is less than the object passed to compareTo().
  • The value zero indicates that both the objects are equal.

Let’s take an example of a JobCandidate class whose objects we want to store in a ArrayList and later sort them. The JobCandidate class has three fields: name and gender of type String and age that is an integer. We want to sort JobCandidate objects stored in the ArrayList based on the age field. To do so, we will need to write the JobCandidate class to implement Comparable and override the compareTo() method.

The code of the JobCandidate class is this.

JobCandidate.java

In the overridden compareTo() method of the JobCandidate class above, we implemented the comparison logic based on the age field. I have seen many programmers restoring to the shortcut version of returning the comparison result as return (this.getAge() - candidate.getAge());. Although using this return statement might appear tempting and will not anyhow affect our example, my advice is to stay away from it. Imagine, the result of comparing integer values where one or both of them are negative values. It can lead to bugs that will make your application behave erratically and more than that, such bugs being subtle, are extremely difficult to detect especially in large enterprise applications. Next, we’ll write a helper class which will sort ArrayList objects containing JobCandidate elements for clients. 

JobCandidateSorter.java

In the JobCandidateSorter class we initialized a ArrayList object that client will pass through the constructor while instantiating JobCandidateSorter. We then wrote the getSortedJobCandidateByAge() method. In this method, we called Collections.sort() passing the initialized ArrayList. Finally, we returned back the sorted ArrayList.

Next, we will write a test class to test our code.

JobCandidateSorterTest.java

In the test class above, we created four JobCandidate objects and added them to an ArrayList. We then instantiated the JobCandidateSorter class passing our ArrayList to its constructor. Finally, we called the getSortedJobCandidateByAge() method of JobCandidateSorter and printed out the sorted ArrayList that the method returns. The output on running the test is this.

Sorting ArrayList using Comparable is a common approach. But, you need to be aware of certain constraints. The class whose object you want to sort must implement Comparable and override the compareTo() method. This essentially means you would only be able to compare the objects based on one field (which was age in our example). What if the requirements state you need to be able to sort JobCandidate objects by name and also by age? Comparable is not the solution. In addition, comparison logic is part of the class whose objects needs to be compared, which eliminates any chance of reusability of the comparison logic. Java addresses such comparison requirements used in sorting by providing the Comparator interface in the java.util package.

Sorting an ArrayList using Comparator

The Comparator interface similar to the Comparable interface provides a single comparison method named compare(). However, unlike the compareTo() method of Comparable, the compare() method takes two different objects of the same type for comparison.
We will use Comparator to sort objects of the same JobCandidate class we used earlier but with few differences. We will allow sorting JobCandidate objects both by name and age by implementing Comparator as anonymous inner classes.

Here is the code of the JobCandidate class using Comparator.

JobCandidate.java

In the class above, from Line 29 – Line 35, we wrote an anonymous class and implemented the compare() method that will allow sorting JobCandidate objects by age in descending order. From Line 37 – Line 42, we again wrote an anonymous class and implemented the compare() method that will allow sorting JobCandidate objects by name in ascending order. We will now write a class that will sort the elements of the ArrayList for clients.

JobCandidateSorter.java

In the class above, we wrote the getSortedJobCandidateByAge() method. In this method we called the overloaded version of Collections.sort() passing the ArrayList object to be sorted and the Comparator object that compares age. In the getSortedJobCandidateByName() method, we again called the overloaded version of Collections.sort() passing the ArrayList object to be sorted and the Comparator object to compare names.

Let’s write a test class to test our code.

JobCandidateSorterTest.java

In the test class we populated JobCandidate objects in an ArrayList and created a JobCandidateSorter object in the JUnit setup() method annotated with @Before. If you are new to JUnit, you can refer my post covering JUnit annotations (Part of a series on unit testing with JUnit) here. In the testGetSortedJobCandidateByAge() test method we called the getSortedJobCandidateByAge() method and printed out the sorted ArrayList that the method returns. In the testGetSortedJobCandidateByName() test method, we called the getSortedJobCandidateByName() method and printed out the sorted ArrayList that the method returns. The output of the test is this.

Conclusion

In this post we looked at different approaches of sorting elements of ArrayList. One using Comparable and the other using Comparator. The approach to choose has always been a cause of confusion for programmers. What you should essentially remember is that a Comparable object can say “I can compare myself with another object” while a Comparator object can say “I can compare two different objects”. You cannot say that one interface is better than the other. The interface you choose depends upon the functionality you need to achieve.

4
Share