In FullComparator , sorting by several fields ( channelName , DateCreated (in reverse order) and Fingerprint ) does not work. Sorts only by the first. What am I doing wrong?

 public class FullComparator implements Comparator<Capability> { @Override public int compare(Capability o1, Capability o2) { if (o1 != null && o2 != null) { if (o1.getChannelName() != null && o2.getChannelName() != null && !o1.getChannelName().equals(o2.getChannelName())) return o1.getChannelName().compareTo(o2.getChannelName()); if (o1.getFingerprint() != null && o2.getFingerprint() != null && !o1.getFingerprint().equals(o2.getFingerprint())) return o1.getFingerprint().compareTo(o2.getFingerprint()); if (o1.getDateCreated() != null && o2.getDateCreated() != null && !o2.getDateCreated().equals(o1.getDateCreated())) return o2.getDateCreated().compareTo(o1.getDateCreated()); } if (o1 == null && o2 != null) return 1; if (o1 != null) return -1; return 0; } } 

 public class Capability implements Comparable<Capability> { private long id; private String channelName; private String fingerprint; private boolean isActive; private Date dateCreated; public Capability(long id, String channelName, String fingerprint, boolean isActive, Date dateCreated) { this.id = id; this.channelName = channelName; this.fingerprint = fingerprint; this.isActive = isActive; this.dateCreated = dateCreated; } public long getId() { return id; } public String getChannelName() { return channelName; } public String getFingerprint() { return fingerprint; } public boolean isActive() { return isActive; } public Date getDateCreated() { return dateCreated; } @Override public String toString() { return "Capability{" + "id=" + id + ", channelName='" + channelName + '\'' + ", fingerprint='" + fingerprint + '\'' + ", isActive=" + isActive + ", dateCreated=" + dateCreated + '}'; } 

 public class DemoComparator { public static void main(String[] args) throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-mm-dd"); Capability capability1 = new Capability(1001, "A", "R", true, sdf.parse("2015-12-15")); Capability capability2 = new Capability(1005, "D", "Z", false, sdf.parse("2010-12-15")); Capability capability3 = new Capability(900, null, "O", true, sdf.parse("2013-12-15")); Capability capability4 = new Capability(900, "B", "L", false, sdf.parse("2008-12-15")); ArrayList<Capability> capabilities = new ArrayList<>(); capabilities.add(capability1); capabilities.add(capability2); capabilities.add(null); capabilities.add(capability4); System.out.println(capabilities); System.out.println(); capabilities.sort(new FullComparator()); System.out.println(capabilities); } } 

And unless the method can sort all fields? Then it turns out that the objects need to change fields so that at the same time, in the final result, all the fields are in the correct order.

  • 1. Add the Capability class to the question code. 2. Why did you decide that sorting does not work? If the channelName matches, the objects are quite self sorted by fingerprint . Similar to dateCreated when the values ​​of the first two fields match. - Regent
  • @Regent Added. Understood. Thank you. - Ruslan Zarichny

1 answer 1

Apparently you do not fully understand the meaning of sorting by several fields. The easiest way to consider the example of students.
The student has a first and last name, as well as a year of birth. There is the following set of students:

  • Ivanov Sergey - 2000
  • Ivanov Artem - 2000
  • Pavel Yakovlev - 2001
  • Sidorov Ruslan - 1999

In this situation, sorting by several fields (Last Name, First Name, Year of Birth -> ascending) assumes that students will first be sorted by last name field, then within groups sorted by last name will be sorted by first name, then inside groups sorted by first and last name sort by year of birth. Thus, at the output we get the following list:

  • Ivanov Artem - 2000
  • Ivanov Sergey - 2000
  • Sidorov Ruslan - 1999
  • Pavel Yakovlev - 2001

If it so happens that another Ivanov Sergey is added to the list, but he was born in 1999, the list will be sorted as follows:

  • Ivanov Artem - 2000
  • Ivanov Sergey - 1999
  • Ivanov Sergey - 2000
  • Sidorov Ruslan - 1999
  • Pavel Yakovlev - 2001

Your code is working and quite copes with the task, to make sure of this, it is enough to add another Capability object to your list:

 Capability capability5 = new Capability(900, "D", "L", false, sdf.parse("2008-12-15")); capabilities.add(capability5); 

This object after sorting will be after the object with channelName A , but before the object with fingerPrint Z


And by the way, if java8 is used, then it is possible to do without the FullComparator class:

 Comparator<Capability> comp = Comparator.nullsLast(Comparator.comparing(Capability::getChannelName).thenComparing(Capability::getFingerprint).thenComparing(Capability::getDateCreated, Comparator.reverseOrder())); capabilities.sort(comp); 

Thus, we literally write: Sort the list so that the null elements are at the end, and sort first by channelName , then by Fingerprint , then by DateCreate in the reverse order.

But be careful, if you want to add capability3 to the list, which has the second argument in the constructor null (as I understand it, channelName ), you will need to write something like:

 Comparator<Capability> comp = Comparator.nullsLast(Comparator.comparing(Capability::getChannelName, Comparator.nullsFirst(Comparator.naturalOrder())).thenComparing(Capability::getFingerprint).thenComparing(Capability::getDateCreated, Comparator.reverseOrder())); capabilities.sort(comp); 

That is all the same, but additionally write that the null values ​​in the channelName when sorting this field were at the beginning.

  • @Regent, the author’s code is working, now I’m adding an answer - Roman Danilov
  • @RomanDanilov Thank you very much for such a detailed answer. Understood. - Ruslan Zarichny
  • @ RuslanZarnichny, success! - Roman Danilov