I have an Employee
object which contains two fields name
and jobTitle
. For sorting the employee objects, first priority should be on jobTitle
, if jobTitle
is null then the sorting should be based on name.
Below is the Employee object
public class Employee {
private String name;
private String jobTitle;
}
I used chained Comparator with JobTitlecomparator
and NameComparator
to achieve this:
public class EmployeeChainedComparator implements Comparator<Employee> {
private List<Comparator<Employee>> listComparators;
@SafeVarargs
public EmployeeChainedComparator(Comparator<Employee>... comparators) {
this.listComparators = Arrays.asList(comparators);
}
@Override
public int compare(Employee emp1, Employee emp2) {
for (Comparator<Employee> comparator : listComparators) {
int result = comparator.compare(emp1, emp2);
if (result != 0) {
return result;
}
}
return 0;
}
}
public class EmployeeJobTitleComparator implements Comparator<Employee> {
@Override
public int compare(Employee emp1, Employee emp2) {
if(emp1.getJobTitle() != null && emp2.getJobTitle() != null){
return emp1.getJobTitle().compareTo(emp2.getJobTitle());
} else {
return 0;
}
}
}
public class EmployeeNameComparator implements Comparator<Employee> {
@Override
public int compare(Employee emp1, Employee emp2) {
return emp1.getName().compareTo(emp2.getName());
}
}
public class SortingMultipleAttributesExample {
public static void main(String[] args) {
List<Employee> listEmployees = new ArrayList<Employee>();
listEmployees.add(new Employee("Tom", "Developer"));
listEmployees.add(new Employee("Sam", null));
listEmployees.add(new Employee("Tim", "Designer"));
listEmployees.add(new Employee("Bob", null));
listEmployees.add(new Employee("Peter", null));
listEmployees.add(new Employee("Craig", "Programmer"));
Collections.sort(listEmployees, new EmployeeChainedComparator(new EmployeeJobTitleComparator(), new EmployeeNameComparator()
));
for(Employee emp : listEmployees){
System.out.println("Employee Job: "+emp.getJobTitle()+" Employee Name: "+emp.getName());
}
}
}
Now I should get the output like this
Employee Job: Designer Employee Name: Tim
Employee Job: Developer Employee Name: Tom
Employee Job: Programmer Employee Name: Craig
Employee Job: null Employee Name: Bob
Employee Job: null Employee Name: Peter
Employee Job null Employee Name: Sam
But I'm not getting the desired result as I expected. I'm getting the output like this
Employee Job Developer Employee Name Tom
Employee Job null Employee Name Sam
Employee Job Designer Employee Name Tim
Employee Job null Employee Name Bob
Employee Job null Employee Name Peter
Employee Job Programmer Employee Name Craig
Can anyone help me on how to achieve this?
If either of the titles is null
, then the two Employee
s will evaluate as equals, even if one of them is not null. That's not what you want. You want all null
titles to be equal to each other, but not non-null values.
Replace your compare method with this:
public int compare(Employee emp1, Employee emp2) {
if(emp1.getJobTitle() == null && emp2.getJobTitle() == null){
return 0;
}
if(emp1.getJobTitle() == null) return 1;
if(emp2.getJobTitle() == null) return -1;
return emp1.getJobTitle().compareTo(emp2.getJobTitle());
}
And you should get the results you expect.
Since you're using Java 8, you can use the built-in comparator facilities instead of creating your own comparators. Comparing the job title and then the name can easily be done with
Comparator<Employee> comparator =
Comparator.comparing(Employee::getJobTitle).thenComparing(Employee:getName);
How to handle null
values is also built-in with the nullsLast
and nullsFirst
methods. Those methods wrap an existing comparator into a null
safe comparator, putting null
values either at the end or at the start.
As such, you can have:
import static java.util.Comparator.comparing;
import static java.util.Comparator.naturalOrder;
import static java.util.Comparator.nullsLast;
// ...
Comparator<Employee> comparator =
comparing(Employee::getJobTitle, nullsLast(naturalOrder())).thenComparing(Employee::getName);
Collections.sort(listEmployees, comparator);
The comparator is created by comparing
the job titles with a null
safe comparator putting null
values last (see also). For equal titles, it is thenComparing
the name of the employees.
来源:https://stackoverflow.com/questions/39518961/comparator-based-on-different-nullable-fields-of-an-object