2013-04-18 62 views
2

下面是代碼導致異常所指示的塊,比較方法拋出一般合同異常

代碼:

  Collections.sort(arrayList, new Comparator() 
      { 
       public int compare(Object o1, Object o2) 
       { 
       TypeAdapterSort tas1 = (TypeAdapterSort) o1; 
       TypeAdapterSort tas2 = (TypeAdapterSort) o2; 
       if (tas1.order < tas2.order) 
        return -1; 
       else 
        return 1; 
       } 
      }); 

例外:

java.lang.IllegalArgumentException: Comparison method violates its general contract! 
        at java.util.TimSort.mergeLo(TimSort.java:747) 
        at java.util.TimSort.mergeAt(TimSort.java:483) 
        at java.util.TimSort.mergeForceCollapse(TimSort.java:426) 
        at java.util.TimSort.sort(TimSort.java:223) 
        at java.util.TimSort.sort(TimSort.java:173) 
        at java.util.Arrays.sort(Arrays.java:659) 
        at java.util.Collections.sort(Collections.java:217) 

當我運行與獨立程序相同的代碼,問題就不會發生。 這裏的比較器有什麼問題? 有沒有辦法在獨立代碼中重現問題?

此問題僅在Java 1.7上發生,因爲Arrays.sort & Collections.sort中的實現發生了更改。如何改變上面的代碼來避免這個問題?另外,如何在獨立代碼中重現此問題?

+0

可能重複。 http://stackoverflow.com/questions/6626437/why-does-my-compare-method-throw-exception-comparison-method-violates-its-gen – 2013-04-18 06:21:19

+0

[比較方法違反其通用合同例外java 7]的可能重複(http://stackoverflow.com/questions/15897892/compare-method-violates-its-general-contract-exception-java-7) – 2013-04-19 07:50:36

+0

停止問多次相同的問題。 – 2013-04-19 07:50:45

回答

4

比較不服從服從總合同。看看這個:

if (tas1.order < tas2.order) 
    return -1; 
else 
    return 1; 
} 

現在考慮兩個對象具有相同的order。他們比較應該返回0

你會更好只是委託給Integer.compare如果您使用的是Java 7:

return Integer.compare(tas1.order, tas2.order); 

或者,如果您使用的是較早版本:

return tas1.order == tas2.order ? 0 
    : tas1.order < tas2.order ? -1 
    : 1; 
+0

謝謝喬恩。但是,爲什麼代碼塊在獨立程序中運行時不會拋出異常。 – Mohan 2013-04-18 06:22:25

+0

@Mohan:那麼你的比較代碼本身並不會檢查它是否遵守'compare'的約定 - 這只是因爲排序代碼*注意到你給它僞造的結果,你會得到一個異常。 – 2013-04-18 06:25:01

+0

謝謝喬恩。在上面的代碼中,如果arraylist具有以Order Order 5,3和1爲例的TypeAdapterSort對象,並且調用Collections.sort方法,則不引發異常。爲什麼這是行爲? – Mohan 2013-04-18 06:41:36

1

您不需要只返回-1或1.總合約指出,如果第一個元素較小,返回的數字必須是負數,如果相等則返回零,如果第二個元素較小,則返回正數。因此,您可以跳過if/else語句並返回:

return tas1.order - tas2.order; 
+1

請考慮'tas1.order'是否爲Integer.MIN_VALUE,而tas2.order是否爲正數... – 2013-04-18 06:25:27