How to write a universal comparator that can sort by all necessary fields?

I needed to sort by all the fields of my class. I wrote a comparator for each field in my class. But I had to write a separate comparator for each field. I think this is not very correct. How to write for my class a single universal comparator that can sort by all fields?

My essence:

public class User { private long id; private String name; private int age; ..................... 

My comparators:

 public class UserComparatorById implements Comparator<User> { public int compare(User user1, User user2) { int result = (int)(user1.getId() - user2.getId()); if (result != 0) return (int)(result/Math.abs(result)); result = user1.getName().compareTo (user2.getName()); if (result != 0) return (int)(result/Math.abs(result)); result = user1.getAge() - user2.getAge(); return (result != 0) ? (int)(result/Math.abs(result)) : 0; } } 

 public class UserComparatorByName implements Comparator<User> { public int compare(User user1, User user2) { int result = user1.getName().compareTo (user2.getName()); if (result != 0) return (int)(result/Math.abs(result)); result = (int)(user1.getId() - user2.getId()); if (result != 0) return (int)(result/Math.abs(result)); result = user1.getAge() - user2.getAge(); return (result != 0) ? (int)(result/Math.abs(result)) : 0; } } 

 public class UserComparatorByAge implements Comparator<User> { public int compare(User user1, User user2) { int result = user1.getAge() - user2.getAge(); if (result != 0) return (int)(result/Math.abs(result)); result = (int)(user1.getId() - user2.getId()); if (result != 0) return (int)(result/Math.abs(result)); result = user1.getName().compareTo (user2.getName()); return (result != 0) ? (int)(result/Math.abs(result)) : 0; } } 

Sorting:

 List<User> users = new ArrayList<User>(); users.add(new User(5, "Frank", 28)); users.add(new User(1, "Jorge", 19)); users.add(new User(6, "Bill", 34)); users.add(new User(3, "Michel", 17)); users.add(new User(7, "Mark", 42)); UserComparatorByName comparatorByName = new UserComparatorByName(); Collections.sort(users, comparatorByName); UserComparatorByAge comparatorByAge = new UserComparatorByAge(); Collections.sort(users, comparatorByAge); 
+4
source share
2 answers

One implementation for each field is not so bad, however there is a lot of duplication in your code. You must have one comparator per field. If you want to compare based on several fields, but in a different order, wrap atomic comparators (Decorator pattern):

 public abstract class AbstractComparator implements Comparator<User> { private final AbstractComparator next; public AbstractComparator(AbstractComparator next) { this.next = next; } public int compare(User user1, User user2) { int result = doCompare(user1, user2); if (result != 0) { return result; } else { return next != null? next.compare(user1, user2) : 0; } } public abstract int doCompare(User user1, User user2); } 

 class ById extends AbstractComparator { public ById(AbstractComparator next) { super(next); } public int doCompare(User user1, User user2) { return (int) (user1.getId() - user2.getId()); } } 

 class ByName extends AbstractComparator { public ByName(AbstractComparator next) { super(next); } public int doCompare(User user1, User user2) { return user1.getName().compareTo(user2.getName()); } } 

 class ByAge extends AbstractComparator { public ByAge(AbstractComparator next) { super(next); } public int doCompare(User user1, User user2) { return user1.getAge() - user2.getAge(); } } 

And use:

 Comparator<User> comp1 = new ById(new ByName(new ByAge(null))); Comparator<User> comp2 = new ByAge(new ByName(new ById(null))); 

comp1 first sorts by id , and if it is equal, returns in name and age as a last resort. The API is pretty straightforward.

For convenience, you should put all By* classes as static inner classes of User : User.ByName , User.ByAge , etc. or perhaps with some factory methods: User.byName(User.byAge(null)) . With some static import you can enjoy the pleasant:

 Collections.sort(users, byName(byAge(byId(null)))); 

Alternatively, you can see CompareToBuilder from Commons Lang.

+5
source

Perhaps the Bean Comparator and Group Comparator will help you.

+2
source

Source: https://habr.com/ru/post/1380664/


All Articles