【问题标题】:Comparison method violates its general contract and method compareTo比较方法违反了它的一般约定和方法 compareTo
【发布时间】:2014-10-13 09:43:22
【问题描述】:

我有一个类Contact,字段为firstNamelastNameemails。我需要使用Collection.sort(...) 对它们进行排序,但我遇到了一个异常:

java.lang.IllegalArgumentException:比较方法违反了它的一般约定!

我的compareTo 方法:

    @Override
public int compareTo(Contact another) {
    int compareFirstName = 0;
    if (this.getFirstName() != null && another.getFirstName() != null) {
        compareFirstName = this.getFirstName().compareToIgnoreCase(
                another.getFirstName());

        if (compareFirstName == 0) {
            int compareLastName = 0;
            if (this.getLastName() != null && another.getLastName() != null) {
                compareLastName = this.getLastName().compareToIgnoreCase(
                        another.getLastName());

                if (compareLastName == 0) {
                    int compareEmail = 0;
                    if (this.getEmails() != null
                            && another.getEmails() != null) {
                        compareEmail = this.getEmails()
                                .compareToIgnoreCase(another.getEmails());

                        return compareEmail;
                    } else {

                        return 0;
                    }
                } else {
                    return compareLastName;
                }
            } else {
                int compareEmail = 0;
                if (this.getEmails() != null && another.getEmails() != null) {
                    compareEmail = this.getEmails().compareToIgnoreCase(
                            another.getEmails());

                    return compareEmail;
                } else {

                    return 0;
                }
            }
        } else {

            return compareFirstName;
        }
    } else {
        int compareLastName = 0;
        if (this.getLastName() != null && another.getLastName() != null) {
            compareLastName = this.getLastName().compareToIgnoreCase(
                    another.getLastName());

            if (compareLastName == 0) {
                int compareEmail = 0;
                if (this.getEmails() != null && another.getEmails() != null) {
                    compareEmail = this.getEmails().compareToIgnoreCase(
                            another.getEmails());

                    return compareEmail;
                } else {

                    return 0;
                }
            } else {

                return compareLastName;
            }
        } else {
            int compareEmail = 0;
            if (this.getEmails() != null && another.getEmails() != null) {
                compareEmail = this.getEmails().compareToIgnoreCase(
                        another.getEmails());

                return compareEmail;
            } else {

                return 0;
            }
        }
    }
}

请帮我找出 compareTo 方法中的错误。谢谢。

【问题讨论】:

  • 你在实现声明中使用泛型吗?可比?
  • 是的。公共类 Contact 实现 FactoryObject, Comparable

标签: java comparison compare comparator compareto


【解决方案1】:

您的实现确实违反了合同。

假设您有 3 个联系人:

contact1 : First Name = "John", Last Name = "Doe", Email = "x@gmail.com"
contact2 : First Name = "John", Last Name = "Doe", Email = null
contact3 : First Name = "John", Last Name = null, Email = "y@gmail.com"

根据你的逻辑:

contact1.compareTo(contact2) 返回 0(因为他们的名字和姓氏相同)。
contact2.compareTo(contact3) 也返回 0(因为您只按名字比较)。
但是contact1.compareTo(contact3) 返回0(因为他们有不同的电子邮件)。

compareTo 必须是可传递的。

解决此问题的方法是不要忽略仅在您正在比较的联系人之一中为空的属性。例如,如果 this.getLastName()==null && another.getLastName() != null,则返回 1(假设您要将 null 姓氏排序在非 null 姓氏之后)。

【讨论】:

  • @dan41k 它不一定会比现在大,因为例如如果 this.getFirstName()==null && another.getFirstName()!=null,你可以立即返回不检查姓氏和电子邮件地址。如果两个名字都为空,则只比较姓氏。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多