当前位置: 首页 > 知识库问答 >
问题:

compareTo比较方法违反了其一般约定

翟高明
2023-03-14

我想通过dateLastContact比较两个“收件人”,如果相同,就通过地址进行比较。这是我的代码:

public class RecipientComparator implements Comparator<Recipient> {
    @Override
    public int compare(Recipient o1, Recipient o2) {
        if (o1.isDateLastContactNull() || o2.isDateLastContactNull()) {
            if (o1.isDateLastContactNull() && o2.isDateLastContactNull()) {
                return o1.getAddress().compareTo(o2.getAddress());
            } else if (o1.isDateLastContactNull()) {
                return -1;
            } else if (o2.isDateLastContactNull()) {
                return -1;
            }
        } else {
            if (o1.getDateLastContact().equals(o2.getDateLastContact())) {
                return o1.getAddress().compareTo(o2.getAddress());
            } else
                return o1.getDateLastContact().compareTo(o2.getDateLastContact());
        }
        return 0;
    }
}

而且我总是有这个错误:

Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.TimSort.mergeHi(TimSort.java:899)
    at java.util.TimSort.mergeAt(TimSort.java:516)
    at java.util.TimSort.mergeCollapse(TimSort.java:439)
    at java.util.TimSort.sort(TimSort.java:245)
    at java.util.Arrays.sort(Arrays.java:1512)
    at java.util.ArrayList.sort(ArrayList.java:1462)
    at managers.RecipientManager.getAllRecipientFromAPI(RecipientManager.java:28)
    at com.company.Main.main(Main.java:18)

我尝试了很多方法,但是现在,我不知道该怎么办。你能帮我吗?

收件人类别:

package recipientPackage;

import paramPackage.Param;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Recipient {
    private String recipientID;
    private String address;
    private String status;
    private int contactCount;
    private Date dateLastContact;
    Param param;
    private String[] attributes = {"recipientID", "address", "status", "contactCount", "dateLastContact"};

    Recipient(String[] recipientBrut, boolean isComeFromMailing) {
        if (isComeFromMailing) {
            createRecipientMailing(recipientBrut);
        } else {
            createRecipientSurvey(recipientBrut);
        }
    }

    public void createRecipientMailing(String[] recipientBrut) {
        this.setRecipientID(recipientBrut[0].substring(recipientBrut[0].indexOf(':') + 1).replaceAll("\"", ""));
        this.setAddress(recipientBrut[1].substring(recipientBrut[1].indexOf(':') + 1).replaceAll("\"", ""));
        this.setStatus(recipientBrut[3].substring(recipientBrut[3].indexOf(':') + 1).replaceAll("\"", ""));

        try {
            this.setDateLastContactForMailing(recipientBrut[5].substring(recipientBrut[5].indexOf(':') + 1).replaceAll("\"", ""));
            this.setContactCount(Integer.parseInt(recipientBrut[4].substring(recipientBrut[4].indexOf(':') + 1).replaceAll("\"", "")));
        } catch (IndexOutOfBoundsException e) {
            this.setDateLastContactForMailing(null);
        }catch (NumberFormatException e){
            e.printStackTrace();
        }
    }

    public void createRecipientSurvey(String[] recipientBrut) {
        setAddress(recipientBrut[0]);
        setStatus(recipientBrut[1]);
        setDateLastContactForSurvey(recipientBrut[2]);
        param.setParam_point_collecte(recipientBrut[5]);
        param.setParam_langue(recipientBrut[6]);
        param.setParam_semaine(recipientBrut[7]);
        param.setParam_periode(recipientBrut[8]);
        param.setParam_envoi(recipientBrut[9]);
        param.setParam_type_visiteur(recipientBrut[10]);
        param.setParam_saison(recipientBrut[11]);
    }

    private void setDateLastContactForMailing(String dateLastContact) {
        if (dateLastContact != null) {
            SimpleDateFormat formatter = new SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss");
            try {
                this.dateLastContact = formatter.parse(dateLastContact);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        } else
            this.dateLastContact = null;

    }

    private void setDateLastContactForSurvey(String dateLastContact) {
        if (!dateLastContact.equals("")) {
            SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
            try {
                this.dateLastContact = formatter.parse(dateLastContact);
            } catch (ParseException ignored) {
            }
        } else
            this.dateLastContact = null;

    }
    public Boolean isDateLastContactNull() {
        return (dateLastContact == null);
    }

    public String getRecipientID() {
        return recipientID;
    }

    public void setRecipientID(String recipientID) {
        this.recipientID = recipientID;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public int getContactCount() {
        return contactCount;
    }

    public void setContactCount(int contactCount) {
        this.contactCount = contactCount;
    }

    public Date getDateLastContact() {
        return dateLastContact;
    }

    public void setDateLastContact(Date dateLastContact) {
        this.dateLastContact = dateLastContact;
    }

    public String[] getAttributes() {
        return attributes;
    }

    public void setAttributes(String[] attributes) {
        this.attributes = attributes;
    }
}

共有2个答案

祖利
2023-03-14

一个显而易见的原因是:

} else if (o1.isDateLastContactNull()) {
    return -1;
} else if (o2.isDateLastContactNull()) {
    return -1;
}

要么o1.isDateLastContNull()truexoro2.isDateLastContNull()true
然后o1

} else if (o1.isDateLastContactNull()) {
    return -1;
} else if (o2.isDateLastContactNull()) {
    return 1;
}

相诚
2023-03-14

您违反了比较方法的契约,您的关系不是可传递的。"实现者必须确保sgns()) == -sgns(比较(y, x))for allxandy"

考虑一下:

public static void main(String[] args){
    Recipient r1; // with isDateLastContactNull() == true;
    Recipient r2; // with isDateLastContactNull() == false;
    RecipientComparator rc = new RecipientComparator();

    System.out.println(rc.compare(r1, r2)); // -1
    System.out.println(rc.compare(r2, r1)); // -1
    // both print -1 which is not transitive.
}

原因是因为这段代码:

if (o1.isDateLastContactNull() && o2.isDateLastContactNull()) {
    // if both null, return comparison of addresses
    return o1.getAddress().compareTo(o2.getAddress());
} else if (o1.isDateLastContactNull()) {
    // if first null, return -1
    return -1;
} else if (o2.isDateLastContactNull()) {
    // if second null, also return -1 ?
    return -1; // should probably be 1 instead
}

对于第二个条件,您可能应该返回 1

合同定义如下:

< code>int compare(T o1,T o2):

比较它的两个顺序参数。当第一个参数小于、等于或大于第二个参数时,返回负整数、零或正整数。在前面的描述中,符号< code>sgn(expression)表示数学符号函数,其被定义为根据expression的值是负、零还是正来返回< code>-1 、< code>0或< code>1之一。

实施者必须确保< code>sgn(compare(x,y)) == -sgn(compare(y,x))对于所有< code>x和< code>y。(这意味着当且仅当< code>compare(y,x)抛出异常时,< code>compare(x,y)必须抛出异常。)

实现者还必须确保关系是可传递的:((比较(x, y)

最后,实现者必须确保对所有z进行比较(x, y)==0,这意味着sgn(比较(x, z))==sgn(比较(y, z))

通常情况下,但不严格要求< code>(compare(x,y)= = 0)=(x . equals(y))。一般来说,任何违反这一条件的比较器都应该清楚地表明这一事实。推荐的语言是“注意:这个比较器强加的排序与equals不一致。”

 类似资料:
  • 我收到以下错误: 比较方法违反了其总合同! 这是我的比较法 我想比较项目的分数。但是当分数相同时,我想按名称对它们进行排序。 我需要更改什么,为什么会出现这个错误? 编辑: 分数是一个,itemname一个。 这是 ComparableItem 类: 这是MenuList项目类:

  • 我知道有很多问题与这个主题有关,但我不能完全理解是什么导致了这个错误 有人知道为什么它不起作用以及如何修复它吗?

  • 问题内容: 我有以下代码: 每次我运行此代码时,都会出现此错误: 我使用OpenJDK7u3,当对象相等时返回0。有人可以向我解释这个错误吗? 问题答案: 如果您有任何NaN值,则可能会遇到这种情况: 例如: 所有 这些打印。因此,您可能会遇到以下两种情况:两个非NaN值都被认为与NaN“相等”,但是一个大于另一个。基本上,您应该弄清楚如何处理NaN值。当然,还要检查这确实是问题所在……您是否真的

  • 我们的一些用户在排序列表时遇到了这个异常。抛出它的代码是 而 getTime() 的类型为 “long”

  • 问题内容: 我看到了很多与此有关的问题,并试图解决该问题,但是经过一个小时的搜索和大量的试验和错误后,我仍然无法修复它。我希望你们中的一些人能抓住问题。 这是我得到的: 这是我的比较器: 任何想法? 问题答案: 异常消息实际上是描述性的。这里所指的合同是传递:如果和那么对于任意的。我用纸和铅笔检查了一下,你的代码似乎有几个孔: 如果你不返回。 如果id不相等,则返回。你应该返回-1或1根据哪个ID

  • 问题内容: 您好,以下是我的比较器的比较方法。我不确定是什么问题。我在堆栈溢出时查找了其他类似标题的问题和答案,但不确定我的方法有什么问题,但我一直在获取java.lang.IllegalArgumentException:比较方法违反了它的一般约定! 任何帮助将不胜感激 添加我得到的异常 问题答案: 您的方法 不是可 传递的 。如果和,则必须等于。 现在考虑这种情况: 对于,和,假设方法返回以下