Different ways to sort a collection of objects in pre and post Java 8
The object we are going to sort is a Person.
public class Person { public enum Gender {FEMALE, MALE}; private String name; private Integer age; private Gender gender; public Person(String name, Integer age, Gender gender) { this.name = name; this.age = age; this.gender = gender; } //getter, setter, equals(...), and hashCode() methods skipped @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", gender=" + gender + "]"; } }
Option 1: Writing your own Comparator implementation. This can be done as an anonymous inner class instead of a separate class.
import java.util.Comparator; public class PersonComparator implements Comparator<Person> { @Override public int compare(Person o1, Person o2) { //by gender first int i1 = o1.getGender().compareTo(o2.getGender()); if (i1 != 0) return i1; //by name next int i2 = o1.getName().compareTo(o2.getName()); if (i2 != 0) return i2; //by age return o1.getAge().compareTo(o2.getAge()); } }
The test class
import java.util.ArrayList; import java.util.List; public class PersonTest { public static void main(String[] args) { List<Person> people = new ArrayList<>(); people.add(new Person("John", 35, Person.Gender.MALE)); people.add(new Person("John", 32, Person.Gender.MALE)); people.add(new Person("Simone", 30, Person.Gender.FEMALE)); people.add(new Person("Shawn", 30, Person.Gender.MALE)); System.out.println("before sorting = " + people); people.sort(new PersonComparator()); System.out.println("after sorting = " + people); } }
Option 2: The Option 1 is not bad, but the the moment you need to handle null element values, the PersonComparator will have more code. One of the best practices in Java is "Don't reinvent the wheel". So, let's use the BeanComparator,NullComparator, and ComparatorChain from the Apache commons library commons-beanutils -> commons-beanutils-bean-collections that uses reflection. The example below also handles null values.
import java.util.ArrayList; import java.util.List; import org.apache.commons.beanutils.BeanComparator; import org.apache.commons.collections.comparators.ComparatorChain; import org.apache.commons.collections.comparators.NullComparator; public class PersonTest { public static void main(String[] args) { List<Person> people = new ArrayList<>(); people.add(new Person("John", 35, Person.Gender.MALE)); people.add(new Person("John", 32, Person.Gender.MALE)); people.add(new Person("Simone", 30, Person.Gender.FEMALE)); people.add(new Person("Shawn", 30, Person.Gender.MALE)); people.add(new Person("Shawn", 30, null)); System.out.println("before sorting = " + people); //Apache commons-beanutils.commons-beanutils-bean-collections ComparatorChain comparatorChain = new ComparatorChain(); //null is compared s lower comparatorChain.addComparator(new BeanComparator("gender", new NullComparator(false))); //null is compared as higher comparatorChain.addComparator(new BeanComparator("name", new NullComparator(true))); comparatorChain.addComparator(new BeanComparator("age", new NullComparator(true))); people.sort(comparatorChain); System.out.println("after sorting = " + people); } }
Option 3: Using the Google Gauva library to sort the collection in functional programming style.
import java.util.ArrayList; import java.util.Comparator; import java.util.List; import com.google.common.collect.ComparisonChain; import com.google.common.collect.Ordering; public class PersonTest { public static void main(String[] args) { List<Person> people = new ArrayList<>(); people.add(new Person("John", 35, Person.Gender.MALE)); people.add(new Person("John", 32, Person.Gender.MALE)); people.add(new Person("Simone", 30, Person.Gender.FEMALE)); people.add(new Person("Shawn", 30, Person.Gender.MALE)); people.add(new Person("Shawn", 30, null)); System.out.println("before sorting = " + people); //anonymous inner class using the Google Gauva library people.sort(new Comparator<Person>() { @Override public int compare(Person o1, Person o2) { return ComparisonChain.start() .compare(o1.getGender(), o2.getGender(), Ordering.natural().nullsFirst()) .compare(o1.getName(), o2.getName(), Ordering.natural().nullsLast()) .compare(o1.getAge(), o2.getAge(), Ordering.natural().nullsLast()) .result(); } }); System.out.println("after sorting = " + people); } }
Option 4: If you are using Java 8, using the functional programming approach.
import java.util.ArrayList; import java.util.Comparator; import java.util.List; public class PersonTest { public static void main(String[] args) { List<Person> people = new ArrayList<>(); people.add(new Person("John", 35, Person.Gender.MALE)); people.add(new Person("John", 32, Person.Gender.MALE)); people.add(new Person("Simone", 30, Person.Gender.FEMALE)); people.add(new Person("Shawn", 30, Person.Gender.MALE)); people.add(new Person("Shawn", 30, null)); System.out.println("before sorting = " + people); //java 8 approach fro multi-fields Comparator<Person> multiFieldComparator = Comparator.comparing(Person::getGender, Comparator.nullsFirst(Comparator.naturalOrder())) .thenComparing(Person::getName, Comparator.nullsLast(Comparator.naturalOrder())) .thenComparing(Person::getAge, Comparator.nullsLast(Comparator.naturalOrder())) ; people.sort(multiFieldComparator); System.out.println("after sorting = " + people); } }
Option 5: If you are using Java 8, using parallel processing. Very similar to option 4, but processed in parallel with minor changes.
import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; public class PersonTest { public static void main(String[] args) { List<Person> people = new ArrayList<>(); people.add(new Person("John", 35, Person.Gender.MALE)); people.add(new Person("John", 32, Person.Gender.MALE)); people.add(new Person("Simone", 30, Person.Gender.FEMALE)); people.add(new Person("Shawn", 30, Person.Gender.MALE)); people.add(new Person("Shawn", 30, null)); System.out.println("before sorting = " + people); Comparator<Person> multiFieldComparator = Comparator.comparing(Person::getGender, Comparator.nullsFirst(Comparator.naturalOrder())) .thenComparing(Person::getName, Comparator.nullsLast(Comparator.naturalOrder())) .thenComparing(Person::getAge, Comparator.nullsLast(Comparator.naturalOrder())) ; //parallel() processing using Fork/Join List<Object> sortedPeople = people.stream() .parallel() .sorted(multiFieldComparator) .collect(Collectors.toList()); System.out.println("after sorting = " + sortedPeople); } }
Output:
before sorting = [Person [name=John, age=35, gender=MALE], Person [name=John, age=32, gender=MALE], Person [name=Simone, age=30, gender=FEMALE], Person [name=Shawn, age=30, gender=MALE], Person [name=Shawn, age=30, gender=null]]
after sorting = [Person [name=Shawn, age=30, gender=null], Person [name=Simone, age=30, gender=FEMALE], Person [name=John, age=32, gender=MALE], Person [name=John, age=35, gender=MALE], Person [name=Shawn, age=30, gender=MALE]]
1 Comments:
Nice Post sir
Post a Comment
Subscribe to Post Comments [Atom]
<< Home