1. 程式人生 > >(有坑)如何正確實現Comparator介面

(有坑)如何正確實現Comparator介面

最近使用者報告了一個crash,錯誤堆疊如下:

java.lang.IllegalArgumentException: Comparison method violates its general contract!
	at java.util.TimSort.mergeHi(TimSort.java:864)
	at java.util.TimSort.mergeAt(TimSort.java:481)
	at java.util.TimSort.mergeForceCollapse(TimSort.java:422)
	at java.util.TimSort.sort(TimSort.java:219)
	at java.util.TimSort.sort(TimSort.java:169)
	at java.util.Arrays.sort(Arrays.java:2010)
	at java.util.Collections.sort(Collections.java:1883)
	at com.xxx.model.c.a(Unknown Source)
	at com.xxx.view.de.doInBackground(Unknown Source)
	at android.os.AsyncTask$2.call(AsyncTask.java:288)
	at java.util.concurrent.FutureTask.run(FutureTask.java:237)
	at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
	at java.lang.Thread.run(Thread.java:841)

這個app運行了一年多還是第一次碰到這個crash。TimSort又是什麼鬼?

簡單的講TimSort是一個優化後的merge sort,比原來的merge sort更穩定、更快。

兩大特點:

1. 對已接近排序和倒序的陣列排序速度異常快。

2. 最差情況仍是O(n*log(n))

JDK7的排序演算法實現改為TimSort。java.util.TimSort的類註釋。

/**
 * A stable, adaptive, iterative mergesort that requires far fewer than
 * n lg(n) comparisons when running on partially sorted arrays, while
 * offering performance comparable to a traditional mergesort when run
 * on random arrays.  Like all proper mergesorts, this sort is stable and
 * runs O(n log n) time (worst case).  In the worst case, this sort requires
 * temporary storage space for n/2 object references; in the best case,
 * it requires only a small constant amount of space.
 *
 * This implementation was adapted from Tim Peters's list sort for
 * Python, which is described in detail here:
 *
 *   http://svn.python.org/projects/python/trunk/Objects/listsort.txt
 *
 * Tim's C code may be found here:
 *
 *   http://svn.python.org/projects/python/trunk/Objects/listobject.c
 *
 * The underlying techniques are described in this paper (and may have
 * even earlier origins):
 *
 *  "Optimistic Sorting and Information Theoretic Complexity"
 *  Peter McIlroy
 *  SODA (Fourth Annual ACM-SIAM Symposium on Discrete Algorithms),
 *  pp 467-474, Austin, Texas, 25-27 January 1993.
 *
 * While the API to this class consists solely of static methods, it is
 * (privately) instantiable; a TimSort instance holds the state of an ongoing
 * sort, assuming the input array is large enough to warrant the full-blown
 * TimSort. Small arrays are sorted in place, using a binary insertion sort.
 *
 * @author Josh Bloch
 */

具體演算法原理這裡不做細究,有興趣的可以研究一下上面註釋中的連結或者論文。

解決方法為在實現Comparator<T>介面時,必須嚴格遵循實現約束,否則會導致執行時異常。 

具體約束為:

  1. sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y
  2. ((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0.
  3. compare(x, y)==0 implies that sgn(compare(x, z))==sgn(compare(y, z)) for all z.

錯誤示例:(JDK6下執行正常,JDK7下會crash)

public class XXXComparator implements Comparator<SomeModel> {

    // 當lhs==rhs時,compare(lhs,rhs)== -1, compare(rhs, lhs)==-1 違背約束1
    @Override
public int compare(SomeModel lhs, SomeModel rhs) {
        if (rhs.value < lhs.value) {
            return 1;
        } else {
            return -1;
        }
    }

}

參考: 


相關推薦

如何正確實現Comparator介面

最近使用者報告了一個crash,錯誤堆疊如下: java.lang.IllegalArgumentException: Comparison method violates its general contract! at java.util.TimSort.merge

1010 Radix - 進位制轉換

思路: 這題有坑啊 (1)z表示36並不意味著只到36進位制,最小2進位制,最大進位制=另一個數的值 (2)可能會超時,用二分 (3)用long long!在二分過程中會溢位,所以要特判,當溢位時說明書過大,right=mid-1 程式碼如下: #include<ios

PAT——乙級1036&乙級1027

乙級1036 1036 跟奧巴馬一起程式設計 (15 point(s)) 美國總統奧巴馬不僅呼籲所有人都學習程式設計,甚至以身作則編寫程式碼,成為美國曆史上首位編寫計算機程式碼的總統。2014 年底,為慶祝“電腦科學教育周”正式啟動,奧巴馬編寫了很

181C】序列字首和,二分,可用set維護

題幹: 小a有n個數,他想把他們劃分為連續的權值相等的k段,但他不知道這是否可行。 每個數都必須被劃分 這個問題對他來說太難了,於是他把這個問題丟給了你。 輸入描述: 第一行為兩個整數n,q,分別表示序列長度和詢問個數。 第二行有n個數,表示序列中的每個數。 接下來

MySQL中ORDER BY與LIMIT一起使用

1.  現象與問題 ORDER BY排序後,用LIMIT取前幾條,發現返回的結果集的順序與預期的不一樣 下面是我遇到的問題: 可以看到,帶LIMIT與不帶LIMIT的結果與我預期的不一樣,而且“很不可思議”,真是百思不得其解 後來百度了一下,如

【CodeForces - 864C】Bus 模擬,

題幹: A bus moves along the coordinate line Ox from the point x = 0 to the point x = a. After starting from the point 

【 CodeForces - 864B】Polycarp and Letters水題,字串,

題幹: Polycarp loves lowercase letters and dislikes uppercase ones. Once he got a string sconsisting only of lowercase and uppercase Latin lett

如何實現多執行緒?實現多執行緒為什麼要調start,而不是run方法?繼承Thread類、實現Ruable介面、Callable<V>

什麼是程序? 作業系統中一個程式的執行週期(從開啟到關閉)。程序是具有一個或多個執行緒的執行緒組。 什麼是執行緒? 一個程序可以同時執行多個任務,任務就是執行緒,一個程序至少有一個執行緒。 執行緒執行在程序內部,執行緒是輕量級程序。 程序和執行緒比較:

【CodeForces - 151D】Quantity of Strings 字串問題,思維推導,

題幹: Just in case somebody missed it: this winter is totally cold in Nvodsk! It is so cold that one gets funny thoughts. For example, let's say the

【CodeForces - 270C】Magical Boxes 思維,進位制,

題幹: Emuskald is a well-known illusionist. One of his trademark tricks involves a set of magical boxes. The essence of the trick is in packing the

【CodeForces - 340B 】Maximal Area Quadrilateral 計算幾何,列舉,

題幹: Iahub has drawn a set of n points in the cartesian plane which he calls "special points". A quadrilateral is a simple polygon withou

【CodeForces - 298C】Parity Game 思維,

題幹: You are fishing with polar bears Alice and Bob. While waiting for the fish to bite, the polar bears get bored. They come up with a game. First

CS231n-KNN實現

從效果看來,KNN並不適合影象識別,它的識別更多基於背景,而不是圖片的語義主體。所以在實際應用中我們一般不適用KNN識別影象,但是在學習過程中,通過KNN演算法我們可以學習到影象識別的整個流程,還是有些許幫助的 影象識別流程 無論是哪種分類演算法,影象識別的流程主要為以下流程

JoyOI1359收入計劃二分

高考結束後,同學們大都找到了一份臨時工作,渴望掙得一些零用錢。從今天起,Matrix67將連續工作N天(1<=N<=100 000)。每一天末他可以領取當天及前面若干天裡沒有領取的工資,但

985D】Sand Fortress 二分,貪心,思維構造,技巧,

題幹: You are going to the beach with the idea to build the greatest sand castle ever in your head! The beach is not as three-dimensional a

2033 】Alphacode dp,

題幹: Alice and Bob need to send secret messages to each other and are discussing ways to encode their messages:  Alice: "Let's just use a

AVL樹插入刪除演算法詳解 -- C++語言實現

一:AVL樹介紹 AVL樹本質上還是一棵二叉搜尋樹,它的特點是: 1.本身首先是一棵二叉搜尋樹。 2.帶有平衡條件:每個結點的左右子樹的高度之差的絕對值(平衡因子)最多為1。在本文中用分別用-1,0,1定義左邊樹高,等高,右邊樹高。平衡因子用m_bf表示。 也就是說,AV

上千萬或上億資料重複,統計其中出現次數最多的N個數據. C++實現

上千萬或上億的資料,現在的機器的記憶體應該能存下。所以考慮採用hash_map/搜尋二叉樹/紅黑樹等來進行統計次數。然後就是取出前N個出現次數最多的資料了,可以用第2題提到的堆機制完成。 #in

伺服器介面呼叫日誌檔案記錄格式

/** * * @Title: writeLocationLog * @Description: 伺服器上寫入操作日誌 * @param type "input"表示入參,“output”表示出參 * @param xml 具體的出入參資訊 * @para