You are here
Home > java >

Use Java8 to make sorting/comparison easy

Use Java8 to make sorting/comparison easyDuring project development, every developer come across a situation where implementation of sorting becomes mandatory. There are many flavors of sorting. It depends on the scenario which one to implement where. In this article, we have mainly focused on sorting using Java 8. Moreover, we have also provided an example which was being used before the introduction of Java 8. Hence our article is on ‘Use Java8 to make sorting/comparison easy’.

There are multiple ways to sort a list of items already available before Java8. Further, Java8 has introduced different ways to make sorting/comparison easy. Let’s get into our topic ‘Use Java8 to make sorting/comparison easy’.

Let’s assume that we have a POJO class Employee as below for the demonstration of various examples.

public class Employee {
    private String name;
    private int age;
    private double salary;
    // generate getters/setters, constructors, toString(), equals() and hashcode() etc. 
}

Don’t forget to override equals() & hashcode() as we are going to compare two objects.

Simple Sort Before Java8 :

Suppose we want to sort by name. Before Java 8, we were used to create an anonymous inner class for the Comparator to sort as below:

new Comparator<Employee>() {
    @Override
    public int compare(Employee e1, Employee e2) {
       return e1.getName().compareTo(e2.getName());
    }
}

This will simply be used to sort List of Employee entities.

public void sortWithoutUsingLambda() {
    List<Employee> employees = Arrays.asList(
       new Employee("George", 10, 10000), 
       new Employee("Robert", 12, 15000),
       new Employee("Kathy", 24, 25000)
    );

    Collections.sort(employees, new Comparator<Employee>() {
    @Override
    public int compare(Employee e1, Employee e2) {
       return e1.getName().compareTo(e2.getName());
    }
});

   for(Employee emp : employees) {
       System.out.println(emp);
   }
}

Simple Sort with Lambdas – Using Java8 to make sorting easy :

In Java8 way, we can now eliminate the anonymous inner class and achieve the same result with simple, functional semantics using lambdas:

(Employee e1, Employee e2) -> e1.getName().compareTo(e2.getName());

We can test it as below:

public void sortingWithLambdaExpression() {
    List<Employee> employees = Arrays.asList(
       new Employee("George", 10, 10000),
       new Employee("Robert", 12, 15000),
       new Employee("Kathy", 24, 25000)
    );

   employees.sort((Employee e1, Employee e2) -> e1.getName().compareTo(e2.getName()));
   employees.forEach(item -> System.out.println(item));
}

Note: Here, we are using the new sort() API added to java.util.List in Java 8 in place of the old Collections.sort API.
We can further simplify the expression by eleminating the type definitions as the compiler is capable of inferring it on its own:

(e1, e2) -> e1.getName().compareTo(e2.getName());

Simple Sort Using Instance Method Reference – Using Java8 to make sorting easy :

By using an instance method reference and the Comparator.comparing method , We can also avoid defining even the comparison logic itself. We will use the getter getName() to build the Lambda expression and sort the list by name:

public void sortingWithMethodReference() {
    List<Employee> employees = Arrays.asList(
       new Employee("George", 10, 10000),
       new Employee("Robert", 12, 15000),
       new Employee("Kathy", 24, 25000)
    );

    Collections.sort(
    employees, Comparator.comparing(Employee::getName));
    employees.forEach(System.out::println);
}

Sort with multiple attributes using Comparator.comparing() : 

Starting with JDK 8, we can first sort by name and then,by age like below code:

public void sortingWithMultipleAttributeUsingMethodReference() {
    List<Employee> employees = Arrays.asList(
       new Employee("George", 10, 10000),
       new Employee("Robert", 12, 15000),
       new Employee("Kathy", 24, 25000)
    );

       employees.sort(
          Comparator.comparing(Employee::getName).thenComparing(Employee::getAge)
       ); 
       employees.forEach(System.out::println);
}

Sorting with Stream.sorted() -Using Java8 to make sorting easy :

We have two overloaded methods of the sorted() API:
sorted() – sorts the elements based on natural ordering; the element class must implement the Comparable interface.
sorted(Comparator<? super T> comparator) – sorts the elements based on a Comparator instance. Hence, we need to pass a comparator instance, as a parameter.
Let’s observe an example of natural ordering:

public void sortNaturallyUsingStream() {
   List<String> alphabets = Arrays.asList("E", "A", "G");

   List<String> sortedAlphabets = alphabets.stream().sorted().collect(Collectors.toList());
   sortedAlphabets.forEach(item->System.out.println(item));
}

Now let’s see an example of Comparator.comparing() with the sorted() API:

public void sortingByNameUsingStream() { 
   List<Employee> employees = Arrays.asList(
      new Employee("George", 10, 10000),
      new Employee("Robert", 12, 15000),
      new Employee("Kathy", 24, 25000)
   );

   List<Employee> sortedEmployees = 
   employees.stream().sorted(Comparator.comparing(Employee::getName)).collect(Collectors.toList());
   sortedEmployees.forEach(item->System.out.println(item));
}

Note: In order to sort in reverse order, reverse the instances as shown below:

Comparator<Employee> reverseNameComparator = 
      (e1, e2) -> e2.getName().compareTo(e1.getName());

How to sort employee by name and salary in java 8?

Below is the code to sort a list of employees by Name and Salary in Java 8 using Streams & Lambda.

     List<Employee> employees = Arrays.asList(
                                    new Employee("George", 10, 10000),
                                    new Employee("Robert", 12, 15000),
                                    new Employee("Kathy", 24, 25000)
                                );

     // Create Comparators for Name and Salary fields respectively
     Comparator<Employee> sortByName = (e1, e2) -> e1.getName().compareToIgnoreCase(e2.getName());
     Comparator<Employee> sortBySalary = (e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary());

     //Sort by Name then Sort by Salary
     employees.stream()
     .sorted(sortByName.thenComparing(sortBySalary))
     .forEach(e->System.out.println(e));

How to sort list of objects by multiple attributes in Java 8?

In order to illustrate the example of sorting a list by multiple attributes, let’s take a Book object as below.

public class Book {

      private Integer id;
      private String name;
      private Integer pages;
      private String author;
      private Double cost;

      public Integer getId() {
         return id;
      }

      public void setId(Integer id) {
         this.id = id;
      }

      public String getName() {
         return name;
      }

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

      public Integer getPages() {
         return pages;
      }

      public void setPages(Integer pages) {
         this.pages = pages;
      }

      public String getAuthor() {
         return author;
      }

      public void setAuthor(String author) {
         this.author = author;
      }

      public Double getCost() {
         return cost;
      }

      public void setCost(Double cost) {
         this.cost = cost;
      }

      public Book(Integer id, String name, Integer pages, String author, Double cost) {
         super();
         this.id = id;
         this.name = name;
         this.pages = pages;
         this.author = author;
         this.cost = cost;
      }

      @Override
      public String toString() {
         return "Book [id=" + id + ", name=" + name + ", pages=" + pages + ", author=" + author + ", cost=" + cost + "]";
      }
}

Now, create a class as below in order to apply the sorting logic.

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

public class SortListByTwoFields {

       public static void main(String[] args) {
          List <Book> bookList = new ArrayList<>();
          bookList.add(new Book(500, "Core Java", 200, "Kathy Sierra", 1065.5));
          bookList.add(new Book(501, "JSP & Servlets", 350, "Kathy Sierra", 1749.0));
          bookList.add(new Book(502, "Spring in Action", 480, "Craig Walls", 940.75));
          bookList.add(new Book(503, "Pro Angular", 260, "Freeman", 1949.25));
          bookList.add(new Book(504, "HTML CSS", 100, "Thomas Powell", 2317.09));
          bookList.add(new Book(505, "Hibernate in Action", 180, "Gavin King", 889.25));

          System.out.println("Sort List of Book objects by BookName");
          //Sort by Name
          bookList.stream()
          .sorted(
               (book1, book2) -> book1.getName().compareToIgnoreCase(book2.getName()) 
          )
          .forEach(
               book-> System.out.println(book)
          );

          // Create Comparators for Name, Author & Cost fields respectively
          System.out.println("\nSort list of book objects by name then by author then by cost");
          Comparator<Book> sortByName = (b1, b2) -> b1.getName().compareToIgnoreCase(b2.getName());
          Comparator<Book> sortByAuthor = (b1, b2) -> b1.getAuthor().compareToIgnoreCase(b2.getAuthor());
          Comparator<Book> sortByCost = (b1, b2) -> Double.compare(b1.getCost(), b2.getCost());

          //Sort by Name then Sort by Author then sort by Cost
          bookList.stream()
          .sorted(
               sortByName
               .thenComparing(sortByAuthor)
               .thenComparing(sortByCost)
          )
          .forEach(
                book-> System.out.println(book)
          ); 
      }
}

Output

On running the program, you will get the expected output.

Sort List of Book objects by BookName
Book [id=500, name=Core Java, pages=200, author=Kathy Sierra, cost=1065.5]
Book [id=505, name=Hibernate in Action, pages=180, author=Gavin King, cost=889.25]
Book [id=504, name=HTML CSS, pages=100, author=Thomas Powell, cost=2317.09]
Book [id=501, name=JSP & Servlets, pages=350, author=Kathy Sierra, cost=1749.0]
Book [id=503, name=Pro Angular, pages=260, author=Freeman, cost=1949.25]
Book [id=502, name=Spring in Action, pages=480, author=Craig Walls, cost=940.75]

Sort list of book objects by name then by author then by cost
Book [id=500, name=Core Java, pages=200, author=Kathy Sierra, cost=1065.5]
Book [id=505, name=Hibernate in Action, pages=180, author=Gavin King, cost=889.25]
Book [id=504, name=HTML CSS, pages=100, author=Thomas Powell, cost=2317.09]
Book [id=501, name=JSP & Servlets, pages=350, author=Kathy Sierra, cost=1749.0]
Book [id=503, name=Pro Angular, pages=260, author=Freeman, cost=1949.25]
Book [id=502, name=Spring in Action, pages=480, author=Craig Walls, cost=940.75]

That’s all about the article ‘Use Java8 to make sorting/comparison easy’. Here, we have covered almost all commonly used ways to implement sorting and comparison especially using Java 8. Once you implement them in your assignment and compare with lower versions than Java 8, you will feel that you are saving too many lines of code for sure.

close

Leave a Reply

Top