How can I improve the comparator for objects by several fields? The comparator must sort user by last name or first name if last name doesn't exist. And if there are no last name and first name sort by username. But these users must be at the end of the list.
public static Comparator<UserConfigurationDto> BY_LASTNAME = (u1, u2) -> {
// if users have only username compare them
if((u1.getLastName().isEmpty() && u1.getFirstName().isEmpty())
&& (u2.getLastName().isEmpty() && u2.getFirstName().isEmpty())){
return u1.getUsername().compareToIgnoreCase(u2.getUsername());
}
//if user doesnt have firstName and LastName drop them at the end
if(u1.getLastName().isEmpty() && u1.getFirstName().isEmpty()){
return 1000000 + getWeight(u1.getUsername());
}
if(u2.getLastName().isEmpty() && u2.getFirstName().isEmpty()){
return -1000000 + getWeight(u2.getUsername());
}
String s1 = u1.getLastName().isEmpty() ? u1.getFirstName() : u1.getLastName();
String s2 = u2.getLastName().isEmpty() ? u2.getFirstName() : u2.getLastName();
return s1.compareToIgnoreCase(s2);
};
}
private static int getWeight(String s){
return s.codePoints().sum();
}
Does anybody have an idea how to improve this? I try to use Comparator.comparing and Comparator.thenComparing but they produce an incorrect result
1) return 1000000 + getWeight(u1.getUsername());
and return -1000000 + getWeight(u2.getUsername());
are not required. return 1
and return -1
is clearer and produces the same result if you refer to the CompareTo()
javadoc :
Compares this object with the specified object for order. Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object
2) You don't chain the field comparisons but you have 3 ways of sorting according to the state of the compared objects. So the fact that the code be a bit verbose to define each case is finally normal.
You could all the same reduce it with an extract method as you duplicate a lot of user.getLastName().isEmpty()
invocations.
For example :
public static Comparator<UserConfigurationDto> BY_LASTNAME = (u1, u2) -> {
// first case
if( u1.isLastAndFirstNameEmpty() && u2.isLastAndFirstNameEmpty()){
return u1.getUsername().compareToIgnoreCase(u2.getUsername());
}
// second case
if(u1.isLastAndFirstNameEmpty()){
return 1;
}
else if(u2.isLastAndFirstNameEmpty()){
return -1;
}
// third case
String s1 = u1.getLastName().isEmpty() ? u1.getFirstName() : u1.getLastName();
String s2 = u2.getLastName().isEmpty() ? u2.getFirstName() : u2.getLastName();
return s1.compareToIgnoreCase(s2);
};