[Java8] Proper use of Comparable and Comparator in terms of employee sorting

Self-introduction

Nice to meet you, my name is @ekuro and I am making a labor management service called Gozal. At Gozal, we are doing domain-driven development to better incorporate labor management into software. We are constantly searching for better and more versatile classes so that we can easily respond to changes in business processes due to work style reforms.

This theme

This time, I thought about "what to use" and "where to define" to sort the list of employees by employee number.

What i did

Premise

Consider the process of sorting the list of employees List <Employee> employees; by employee number.

Employee.java


@Getter
@AllArgsConstructor
public class Employee {
  //employee number
  private EmployeeNumber number;
  //Personal information such as name and date of birth
  private Personal personal;
}

@Getter
@AllArgsConstructor
public class EmployeeNumber {
  private String number;
}

Sort method

Typical methods for sorting objects in Java 8 are Collections.sort and the Sorted method of the Stream API.

When using Collections, you will need to use one of the following two sort methods.

public static <T extends Comparable<? super T>> void sort(List<T> list) {
  list.sort(null);
}
public static <T> void sort(List<T> list, Comparator<? super T> c) {
  list.sort(c);
}

Also, when using the Stream API, two types of methods are also provided.

Stream<T> sorted();
Stream<T> sorted(Comparator<? super T> comparator);

In either case, when using the first method, the class to be sorted must implement Comparable, and when using the second method, the functional interface Comparator is used as an argument. Must be passed in.

Both Comparable and Comparator are classes that define magnitude comparisons, but let's first look at the differences.

Difference between Comparable and Comparator

Comparable is an interface where only public int compareTo (To); is defined. By making the object you want to compare inherit Comparable and implementing compareTo, you can define how to compare that object. The compareTo method compares the argument with itself. On the other hand, the Comparator interface defines a method that has two arguments, ʻint compare (To1, To2); `. Since you can implement multiple Comparator for the objects you want to compare, it is useful when you want to define sorting by various keys.

For Employee

Consider the case of the Employee class. The Employee class has personal information such as name in addition to the employee number. Therefore, it is possible to sort by various information in the future. Therefore, it seems better to create a Comparator for each item to be compared instead of inheriting Comparator in the Employee class.

Let's write a method that actually returns a Comparator to sort the employee list by employee number. [^ 1]

Employee.java


@Getter
@AllArgsConstructor
public class Employee {
  //employee number
  private EmployeeNumber number;
  //Personal information such as name and date of birth
  private Personal personal;

  public static Comparator<Employee> orderByNumber() {
    return Comparator.comparing(
      //Simple employee number string comparison
      (Employee employee) -> employee.getNumber().getNumber());
  }
}

When actually sorting,

List<Employee> employees = ~;
Collections.sort(employees, Employee.orderByNumber());

Can be written.

Perform comparison processing in the appropriate place

In the above example, the comparison method ʻorderByNumber ()` is defined in the Employee class. However, by nature, comparing employee numbers is a property that employee number classes should have. So move the comparison method to the EmployeeNumber class.

Employee.java


@Getter
@AllArgsConstructor
public class Employee {
  //employee number
  private EmployeeNumber number;
  //Personal information such as name and date of birth
  private Personal personal;

  public static Comparator<Employee> orderByNumber() {
    //Using EmployeeNumber as the key for comparison, the sorting process is left to the order method of EmployeeNumber.
    return Comparator.comparing(Employee::getNumber, EmployeeNumber.order());
  }
}

EmployeeNumber.java


@Getter
@AllArgsConstructor
public class EmployeeNumber {
  private String number;
  
  public static Comparator<EmployeeNumber> order() {
    return Comparator.comparing(EmployeeNumber::getNumber);
  }
}

The comparison method was completed with EmployeeNumber, making it a more versatile class. This time, the size comparison process of EmployeeNumber is a simple logic, but if numbers and character strings are mixed, it will be a little complicated process. In that case, it will be better to see if the comparison process is defined in EmployeeNumber.

Think again if you can use Comparable

Since multiple Comparators can be defined for one object, it is easy to use them a lot. So check if you have used Comparator where you should inherit Comparable.

It seems that the sorting of Employee Number this time will not be sorted by anything other than number in the future. Therefore, it is better to use Comparable for Employee Number comparison processing.

Employee.java


@Getter
@AllArgsConstructor
public class Employee {
  //employee number
  private EmployeeNumber number;
  //Personal information such as name and date of birth
  private Personal personal;

  public static Comparator<Employee> orderByNumber() {
    //EmployeeNumber implements Comparable, which reduces the number of arguments.
    return Comparator.comparing(Employee::getNumber);
  }
}

EmployeeNumber.java


@Getter
@AllArgsConstructor
public class EmployeeNumber implements Comparable<EmployeeNumber> {
  private String number;
  
  @Override
  public int compareTo(@Nonnull EmployeeNumber other) {
    return this.number.compareTo(other.number);
  }
}

By inheriting Comparable from EmployeeNumber, unnecessary description is eliminated and the processing content is refined.

By writing the appropriate processing in the appropriate place in this way, it will be possible to smoothly respond to requests such as "I want to sort by name" and "I want to sort by birthday" in the future.

We believe that better understanding of concepts and designing classes will not only make it easier to implement and provide easy-to-understand source code, but will also lead to the discovery of more sophisticated new business flows.

At Gozal, we will stick to how to grasp the concept in order to create a new work experience that will make the world stunning by sending engineers.

Recruiting engineers from the world of labor management to eliminate unnecessary manual work! Recruiting front engineers to create a moving labor management SaaS!

[^ 1]: The static comparing method provided in the Comparator interface takes Function as an argument and compares the result of Function with compareTo when there is only one argument.

Recommended Posts

[Java8] Proper use of Comparable and Comparator in terms of employee sorting
Use of Abstract Class and Interface properly in Java
Proper use of redirect_to and render
Proper use of Mockito and PowerMock
Whether to use Java Comparable or Comparator
Proper use of interface and abstract class
Discrimination of Enums in Java 7 and above
(Determine in 1 minute) About the proper use of empty ?, blank? And present?
[Java] Use of final in local variable declaration
Criteria for proper use of render and redirect_to
Basics of threads and Callable in Java [Beginner]
Why use setters/getters instead of public/private in Java
Sorting using java comparator
Use of Japanese fonts and external characters in JasperReport
Use OpenCV in Java
Use PreparedStatement in Java
Handling of date and time in Ruby. Use Date and Time properly.
[For beginners] Explanation of classes, instances, and statics in Java
How to call and use API in Java (Spring Boot)
Reasons to use Servlet and JSP separately in Java development
[Java] Comparator of Collection class
Comparable and Comparator (ordering objects)
Implementation of gzip in java
Advantages and disadvantages of Java
Use Redis Stream in Java
Implementation of tri-tree in Java
[Java] Basic terms in programming
Mechanism and characteristics of Collection implementation class often used in Java
Use java with MSYS and Cygwin
About fastqc of Biocontainers and Java
Encoding and Decoding example in Java
Let's use Twilio in Java! (Introduction)
Use JDBC with Java and Scala.
[Java] Do not use "+" in append!
Use composite keys in Java Map.
StringBuffer and StringBuilder Class in Java
List of members added in Java 9
[Java] Judgment of identity and equivalence
Understanding equals and hashCode in Java
How to use classes in Java?
List of types added in Java 9
Implementation of like function in Java
Do you use Stream in Java?
Hello world in Java and Gradle
JSON in Java and Jackson Part ③ Embed JSON in HTML and use it from JavaScript
The story of forgetting to close a file in Java and failing
Use static initialization block to initialize List / Set of static fields in Java
Sorting AtCoder ABC 111 C hashes to solve in Ruby, Perl and Java
What wasn't fair use in the diversion of Java APIs on Android
This and that of the implementation of date judgment within the period in Java
Comparison of thread implementation methods in Java and lambda expression description method
[Java] Note how to use RecyclerView and implementation of animated swipe processing.
Find the maximum and minimum of the five numbers you entered in Java
Review of "strange Java" and Java knowledge that is often forgotten in Java Bronze