为什么我的比较methd有时会抛出IllegalArgumentException? [英] Why does my compare methd throw IllegalArgumentException sometimes?

查看:197
本文介绍了为什么我的比较methd有时会抛出IllegalArgumentException?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个问题已经有一段时间了,已经搜索了很多StackOverflow问题,但无法解决我的问题。

I am having this problem for some time, have searched lots of StackOverflow questions but couldn't solve my problem.

我之前也问了类似的问题建议使用,

I also asked a similar question before and got the suggestion to use,

System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

它没有解决我的问题。我的任何测试设备上都没有这个例外,但我的一些用户已经定期报告。我真的很无能解决它。

It didn't solve my problem. I never got this exception on any of my test devices, but some of my users have been reporting it regularly. I am really clueless how to solve it.

例外

这是我得到的例外,

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)

或有时这个,

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)

我做了什么

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;
            }
        };
    }
}

这就是我的排序方式,

Collections.sort(dirs, FileItemComparator.getComparator(FileItemComparator.NAME_SORT));

问题

我确信比较方法中存在传递依赖性的错误。我已经尝试了很多,似乎无法解决它。实际上,我的任何测试设备都没有遇到过这个问题,但是我的用户不断报告这个问题。

I am sure there is something wrong in the compare method with transitive dependencies. I have tried a lot and can't seem to fix it. Actually, I never got this problem in any of my test devices, but my users are reporting it constantly.

我希望这里的任何人都能解决问题并提供帮助我一劳永逸地解决这个问题。

I hope anyone here will be able to catch the problem and help me solve it once and for all.

更新代码(感谢@Eran)

我认为最好通过发布完整的更新代码来帮助他人。它将帮助很多人面临同样的问题。

I thought it would be best to help others by posting the complete updated code. It will help a lot of people facing 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;
            }
        };
    }
}


推荐答案

让我们来吧看看你的第一个比较方法:

Let's look at your first compare method :

    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;
    }

假设您正在比较两个FileItem(让我们称之为o1和o2),一个带有文件名而另一个没有(即空文件名)。您的方法将返回0.

Suppose you are comparing two FileItems (let's call them o1 and o2), one with a file name and the other without (i.e. null file name). Your method will return 0.

现在,如果将o2与文件名不为null的另一个FileItem(o3)进行比较,则再次返回0。

Now if you compare o2 with another FileItem (o3) for which the file name is not null, you return 0 again.

但是如果将o1与o3进行比较,因为它们都具有非空文件名,比较返回-1或1(假设文件名不同)。

But if you compare o1 to o3, since both of them have non null file name, the comparison returns -1 or 1 (assuming the file names are different).

因此,您的比较不一致,因为它不具有传递性。

Therefore your comparison is inconsistent since it's not transitive.

如果一个元素缺少比较所需的属性而另一个元素没有,则不应返回0.您应该决定是返回1还是-1(例如,取决于是否应在具有非空名称的FileItem之前或之后对具有空名称的FileItem进行排序。)

If one element lacks a property required for the comparison and the other doesn't, you shouldn't return 0. You should decide whether to return 1 or -1 (depending whether, for example, the FileItems with null names should be ordered before or after the FileItems with non null names).

例如:

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);
}

这篇关于为什么我的比较methd有时会抛出IllegalArgumentException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆