2014-10-13 2 views
0

У меня есть класс Contact с полями firstName, lastName и emails. Мне нужно, чтобы отсортировать их с помощью Collection.sort(...), но я получил исключение:Метод сравнения нарушает его общий договор и метод compareTo

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. Благодарю.

+0

Вы используете дженерики в реализации declerarion? Сопоставимый ? – MadProgrammer

+0

Да. public class Contact реализует FactoryObject, Comparable dan41k

ответ

2

Ваша реализация нарушает договор.

Предположим, у вас есть 3 Контакты:

contact1 : First Name = "John", Last Name = "Doe", Email = "[email protected]" 
contact2 : First Name = "John", Last Name = "Doe", Email = null 
contact3 : First Name = "John", Last Name = null, Email = "[email protected]" 

Основываясь на вашей логике:

contact1.compareTo (Contact2) возвращает 0 (поскольку они имеют такое же имя и фамилию).
контакт2.compareTo (контакт3) также возврат 0 (так как вы только сравниваете по имени).
Но contact1.compareTo (contact3) не возврат 0 (так как у них разные адреса электронной почты).

compareTo должно быть транзитивным.

Способ исправить это не значит игнорировать свойство, которое является нулевым только в одном из контактов, которые вы сравниваете. Например, если this.getLastName() == null & & another.getLastName()! = Null, return 1 (при условии, что вы хотите заказать фамилии null после непустых фамилий).

+0

Спасибо. Я понимаю свою проблему ... Теперь мой метод будет огромным ... – dan41k

+0

@ dan41k Это не обязательно будет больше, чем сейчас, поскольку, например, если this.getFirstName() == null && another.getFirstName ()! = null, вы можете немедленно вернуться без проверки имени и адреса электронной почты. Вы сравниваете только последние имена, если оба имени имеют нулевое значение. – Eran