這個坑,你要注意:Comparison method violates its general contract!
阿新 • • 發佈:2019-02-19
背景
有部分業務需要進行排序,對比的物件是某實體裡的金額(double 型別),這樣,我們實現了自定義的比較類,結果執行一段時間之後報了錯誤:Comparison method violates its general contract! ,經過校驗,發現錯誤出現在自定義排序上,經網上各種查閱資料發現是jdk7的相容問題,以下將解決過程分享給大家。
錯誤截圖:
重寫的比較方法:
解決方案
先說如何解決,解決方式有兩種。
修改程式碼
上面程式碼寫的本身就有問題,第4行沒有考慮o1 == o2的情況,再者說我們不需要自己去比較,修改為如下程式碼即可:
/** * 對比類:根據持有金額 */ private static class TenderCollectComparator implements Comparator<TenderCollect> { public int compare(TenderCollect b1, TenderCollect b2) { return b1.getTocollectmoney().compareTo(b2.getTocollectmoney()); } }
不修改程式碼
那麼問題來了。為什麼上面程式碼在JDK6中執行無問題,而在JDK7中卻會拋異常呢?這是因為JDK7底層的排序演算法換了,如果要繼續使用JDK6的排序演算法,可以在JVM的啟動引數中加入如下引數:
[plain] view plain copy print?- -Djava.util.Arrays.useLegacyMergeSort=true
分析
在我以前的認知中,高版本的JDK是可以相容之前的程式碼的,與同事討論了一番另加搜尋了一番,事實證明,JDK6到JDK7確實存在相容問題(不相容列表)。在不相容列表中我們可以找到關於Collections.sort的不相容說明,如下:
- Area: API: Utilities
- Synopsis: Updated sort behavior for Arrays and Collections may throw an IllegalArgumentException
- Description: The sorting algorithm used by java.util.Arrays.sort and (indirectly) by java.util.Collections.sort has been replaced.
- The new sort implementation may throw an IllegalArgumentException if it detects a Comparable that violates the Comparable contract.
- The previous implementation silently ignored such a situation.
- If the previous behavior is desired, you can use the new system property, java.util.Arrays.useLegacyMergeSort,
- to restore previous mergesort behavior.
- Nature of Incompatibility: behavioral
- RFE: 6804124
- sgn(compare(x, y)) == -sgn(compare(y, x))
- ((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0
- compare(x, y)==0 implies that sgn(compare(x, z))==sgn(compare(y, z)) for all z
- return x > y ? 1 : -1;
結論
那麼現在是否可以蓋棺定論了,按照上面的分析來看,使用這種比較方式(return x > y ? 1 : -1;),只要集合或陣列中有相同的元素,就會丟擲本文標題的異常。實則不然,什麼情況下丟擲異常,還取決於JDK7底層排序演算法的實現,也就是大名鼎鼎的TimSort。後面文章會分析TimSort。本文給出一個會引發該異常的Case,以便有心人共同研究,如下:[java] view plain copy print?- Integer[] array =
- {0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,