background

Note the previous example of a call to collections.sort () causing an App Crash. For service reasons, you need to sort files in the main App. The sorting rule is to sort the files in ascending order according to the latest modification time, and then delete the list of files whose modification time is shorter to realize simple clearing cache function. But after simple implementation, annotations to throw out a Java lang. IllegalArgumentException: Comparison method violates its general contract! .

Haha let’s rock!

To analyze problems

The problem code is as follows:

 Collections.sort(child, new Comparator<File>() {
        @Override
        public int compare(File lFile, File rFile) {
            Long lModified = lFile.lastModified();
            Long rModified = rFile.lastModified();
            returnlModified.compareTo(rModified); }});Copy the code

Does it seem like there’s nothing wrong with the code at first glance? Yes, I did at first. But read on to see what went wrong.

Say to the Collections. The sort () and Java. Lang. IllegalArgumentException: Comparison method violates its general contract! This crash, I believe we have baidu probably because of what reason. Yes, collections.sort () implements a different underlying sort algorithm in JDK6 and JDK7, using MergeSort in JDK6 and TimSort in JDK7. The TimSort algorithm is more demanding than the TimSort algorithm:

The Comparator’s Comparator requires:

1 sgn(compare(x, y)) == -sgn(compare(y, x))
2 ((compare(x, y)>0) && (compare(y, z)>0))
3If you compare (x, y) = =0Compare (x, z))== compare(y, z)Copy the code

For example, let’s have the following code:

 Collections.sort(child, new Comparator<Integer>() {
        @Override
        public int compare(Integer l, Integer r) {
            return l > r ? 1 : -1; }});Copy the code

Congratulations, crash. Compare (l,r) is not the same as compare(r, L), and TimSort detects this exception and GG is generated.

But! But!

The above code:

 Collections.sort(child, new Comparator<File>() {
        @Override
        public int compare(File lFile, File rFile) {
            Long lModified = lFile.lastModified();
            Long rModified = rFile.lastModified();
            returnlModified.compareTo(rModified); }});Copy the code

What seems to be the problem? Call the SDK internal implementation of compareTo, in fact, there is no problem in this, but it ignores a situation:

File is null!

File is null!

File is null!

NullPointException is not declared, so you might say, “I can guarantee that File is not null.”

For the simple reason that the JVM doesn’t know. As simple as that, because the JVM is insensitive to your code, it has no way of knowing if File is necessarily non-empty, so the JVM will assume File is null, fail to determine whether the comparison is correct, and throw an exception.

To solve the problem

If File is null or File does not exist, the code is as follows:

    Collections.sort(child, new Comparator<File>() {
        @Override
        public int compare(File lFile, File rFile) {
            boolean lInValid = (lFile == null| |! lFile.exists());boolean rInValid = (rFile == null| |! rFile.exists());boolean bothInValid = lInValid && rInValid;
            if (bothInValid) {
                return 0;
            }

            if (lInValid) {
                return -1;
            }

            if (rInValid) {
                return 1;
            }

            Long lModified = lFile.lastModified();
            Long rModified = rFile.lastModified();
            returnlModified.compareTo(rModified); }});Copy the code

And then the problem was solved perfectly.

conclusion

java.lang.IllegalArgumentException:Comparison method violates its general contract! This exception is really crappy, and it’s very easy to throw exceptions when using collections.sort, so be very careful when writing the collections.sort logic, and if possible, use the compareTo method implemented in the SDK, which is much less crappy.

Reprint please indicate the source, my public number: hashi students