Сравнивать метод сравнения нарушает его общий контракт - PullRequest
0 голосов
/ 11 декабря 2018

Я хочу сравнить двух «Получателей» по 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 ]

0 голосов
/ 11 декабря 2018

Одна очевидная причина заключается в следующем:

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

либо o1.isDateLastContactNull() равно true xor o2.isDateLastContactNull() равно trueтогда o1 < o2.Возможно, вы имели в виду:

} else if (o1.isDateLastContactNull()) {
    return -1;
} else if (o2.isDateLastContactNull()) {
    return 1;
}
0 голосов
/ 11 декабря 2018

Вы нарушаете договор метода сравнения, ваши отношения не являются переходными. "Разработчик должен убедиться, что sgn(compare(x, y)) == -sgn(compare(y, x)) для всех x и y"

Учитывайте следующее:

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 для второго условия.


Контракт такой, как здесь определен:

int compare(T o1, T o2):

Сравнивает два аргумента для порядка.Возвращает отрицательное целое число, ноль или положительное целое число, так как первый аргумент меньше, равен или больше второго.В вышеприведенном описании обозначение sgn(expression) обозначает математическую функцию signum, которая определена для возврата одного из -1, 0 или 1 в зависимости от того, является ли значение выражения отрицательным, нулевым или положительным.

Разработчик должен убедиться, что sgn(compare(x, y)) == -sgn(compare(y, x)) для всех x и y.(Это означает, что compare(x, y) должно выдавать исключение тогда и только тогда, когда compare(y, x) выдает исключение.)

Разработчик также должен обеспечить транзитивность отношения: ((compare(x, y) > 0) && (compare(y, z) > 0)) подразумевает compare(x, z) > 0.

Наконец, разработчик должен убедиться, что compare(x, y) == 0 подразумевает, что sgn(compare(x, z)) == sgn(compare(y, z)) для всех z.

Обычно это так, но строго не требуется, чтобы (compare(x, y) == 0) == (x.equals(y)).Вообще говоря, любой компаратор, который нарушает это условие, должен четко указывать этот факт.Рекомендованный язык: «Примечание: этот компаратор устанавливает порядок, не совместимый с равным».

...