I had this problem for some time, you searched a lot of StackOverflow questions, but could not solve my problem.
I also asked a similar question before and got an offer to use,
System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
This did not solve my problem. I have never received this exception on any of my test devices, but some of my users have reported this regularly. I really don't know how to solve it.
An exception
This is the exception that I get
java.lang.IllegalArgumentException: Comparison method violates its general contract! at java.util.TimSort.mergeLo(TimSort.java:743) at java.util.TimSort.mergeAt(TimSort.java:479) at java.util.TimSort.mergeCollapse(TimSort.java:404) at java.util.TimSort.sort(TimSort.java:210) at java.util.TimSort.sort(TimSort.java:169) at java.util.Arrays.sort(Arrays.java:2023) at java.util.Collections.sort(Collections.java:1883)
or sometimes it
java.lang.IllegalArgumentException: Comparison method violates its general contract! at java.util.TimSort.mergeHi(TimSort.java:864) at java.util.TimSort.mergeAt(TimSort.java:481) at java.util.TimSort.mergeCollapse(TimSort.java:406) at java.util.TimSort.sort(TimSort.java:210) at java.util.TimSort.sort(TimSort.java:169) at java.util.Arrays.sort(Arrays.java:2010) at java.util.Collections.sort(Collections.java:1883)
What I've done
enum FileItemComparator implements Comparator<FileItem> { //Using ENUM NAME_SORT { public int compare(FileItem o1, FileItem o2) { int result = 0; if (o1 != null && o2 != null) { String n1 = o1.getFileName(); String n2 = o2.getFileName(); if (n1 != null && n2 != null) result = n1.compareTo(n2); } return result; } }, DATE_SORT { public int compare(FileItem o1, FileItem o2) { int result = 0; if (o1 != null && o2 != null) { String d1 = o1.getFileDate(); String d2 = o2.getFileDate(); if (d1 != null && d2 != null) { Long l1 = Long.valueOf(d1); Long l2 = Long.valueOf(d2); if (l1 != null && l2 != null) { result = l1.compareTo(l2); } } } return result; } }, SIZE_SORT { public int compare(FileItem o1, FileItem o2) { int result = 0; if (o1 != null && o2 != null) { File f1 = o1.getItem(); File f2 = o2.getItem(); if (f1 != null && f2 != null) { result = Long.valueOf(f1.length()).compareTo(Long.valueOf(f2.length())); } } return result; } }; public static Comparator<FileItem> descending(final Comparator<FileItem> other) { return new Comparator<FileItem>() { public int compare(FileItem o1, FileItem o2) { return -1 * other.compare(o1, o2); } }; } public static Comparator<FileItem> getComparator(final FileItemComparator... multipleOptions) { return new Comparator<FileItem>() { public int compare(FileItem o1, FileItem o2) { for (FileItemComparator option : multipleOptions) { int result = option.compare(o1, o2); if (result != 0) { return result; } } return 0; } }; } }
This is how I sort
Collections.sort(dirs, FileItemComparator.getComparator(FileItemComparator.NAME_SORT));
Problem
I am sure there is something wrong with the transitive dependencies in the comparison method. I tried a lot and it seems I canโt fix it. In fact, I have never had this problem on any of my test devices, but my users are constantly reporting this.
I hope someone here can catch the problem and help me solve it once and for all.
Updated code (thanks to @Eran)
I thought it was best to help others by posting a full updated code. This will help many people faced with the same problem.
enum FileItemComparator implements Comparator<FileItem> { //Using ENUM NAME_SORT { public int compare(FileItem o1, FileItem o2) { if (o1 == null) { if (o2 == null) { return 0; } else { return 1; // this will put null in the end } } else if (o2 == null) { return -1; } String n1 = o1.getFileName(); String n2 = o2.getFileName(); if (n1 == null) { if (n2 == null) { return 0; } else { return 1; // this will put null names after non null names } } else if (n2 == null) { return -1; } return n1.compareTo(n2); } }, DATE_SORT { public int compare(FileItem o1, FileItem o2) { if (o1 == null) { if (o2 == null) { return 0; } else { return 1; // this will put null in the end } } else if (o2 == null) { return -1; } String d1 = o1.getFileDate(); String d2 = o2.getFileDate(); if (d1 == null) { if (d2 == null) { return 0; } else { return 1; // this will put null names after non null names } } else if (d2 == null) { return -1; } Long l1 = Long.valueOf(d1); Long l2 = Long.valueOf(d2); if (l1 == null) { if (l2 == null) { return 0; } else { return 1; // this will put null names after non null names } } else if (l2 == null) { return -1; } return l1.compareTo(l2); } }, SIZE_SORT { public int compare(FileItem o1, FileItem o2) { if (o1 == null) { if (o2 == null) { return 0; } else { return 1; // this will put null in the end } } else if (o2 == null) { return -1; } File f1 = o1.getItem(); File f2 = o2.getItem(); if (f1 == null) { if (f2 == null) { return 0; } else { return 1; // this will put null in the end } } else if (f2 == null) { return -1; } Long l1 = Long.valueOf(f1.length()); Long l2 = Long.valueOf(f2.length()); if (l1 == null) { if (l2 == null) { return 0; } else { return 1; // this will put null names after non null names } } else if (l2 == null) { return -1; } return l1.compareTo(l2); } }; public static Comparator<FileItem> descending(final Comparator<FileItem> other) { return new Comparator<FileItem>() { public int compare(FileItem o1, FileItem o2) { return -1 * other.compare(o1, o2); } }; } public static Comparator<FileItem> getComparator(final FileItemComparator... multipleOptions) { return new Comparator<FileItem>() { public int compare(FileItem o1, FileItem o2) { for (FileItemComparator option : multipleOptions) { int result = option.compare(o1, o2); if (result != 0) { return result; } } return 0; } }; } }