Collections.sort()崩潰分析
對List排序一般採用兩種方法:
(1)實體類實現Comparable<T>
介面,完成compareTo(T o)
方法。
(2)建立一個Comparator<T>
的實現類,完成compare(T o1, T o2)
方法,然後利用這個比較器對List進行排序。
詳情可以看一下我的這篇文章。
當我們書寫compareTo(T o)
或compare(T o1, T o2)
方法時,我們知道:當第一個引數小於第二個引數時返回負整數;當第一個引數等於第二個引數時返回0;當第一個引數大於第二個引數時返回正整數。
但一定要記住3個原則:
1. 確保:sgn(compare(x, y)) == -sgn(compare(y, x)).
2. 確保:如果((compare(x, y)>0) && (compare(y, z)>0)),那麼compare(x, z)>0.
3. 確保:如果compare(x, y)==0,那麼對於任意的z都有sgn(compare(x, z))==sgn(compare(y, z))成立.
sgn(expression)是一個數學正負號函式,根據expression是負數、0、正數分別返回-1、0、1。
可以不實現equals()方法,也不一定要求(compare(x, y)==0) == (x.equals(y))。但建議正確實現各個方法。
由於JDK7之前Collections.sort
Arrays.sort
所使用的排序演算法並沒有對此做嚴格的限制,所以可以在x、y相等的時候不返回0,但JDK7之後採用更高效的TimSort演算法進行排序,就需要嚴格遵循上面的3個原則,否則就會出現下面這樣的異常:
Exception in thread “main” java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.TimSort.mergeHi(Unknown Source)
at java.util.TimSort.mergeAt(Unknown Source)
at java.util.TimSort.mergeForceCollapse(Unknown Source)
at java.util.TimSort.sort(Unknown Source)
at java.util.Arrays.sort(Unknown Source)
at java.util.ArrayList.sort(Unknown Source)
at java.util.Collections.sort(Unknown Source)
at cn.test.JDK7.main(JDK7.java:32)
該異常並不是總會出現,只有當集合中元素順序影響到演算法排序時才會出現(如TimSort在Merge過程中出觸發了“勝利N次”優化,並且A[base1]==A[base1+x])&&(A[base1+x]==B[base2]時,具體可以看一下原始碼中mergeLo()和mergeHi()方法的實現),所以在開發環境下很難復現這個異常,通常只會在產品環境下發現。所以為了遵循原則,也是為了養成良好的程式設計習慣,一定要正確實現比較器。
下面是一個會出現異常的Case:
package cn.test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class JDK7 {
private static final String SORT_TIME_VALUE = "sort_time_value";
private static final String PRICE_DOLLAR = "price_dollar";
private static ArrayList<GameBean> gameBeans = new ArrayList<>();
public static void main(String[] args) {
add("0", 7);
add("3", 1);
add("0", 25);
add("1", 2);
add("0", 2);
add("1", 1);
add("0", 1);
add("1", 1);
add("0", 4);
add("1", 1);
add("0", 2);
add("1", 1);
add("0", 3);
add("2", 1);
add("1", 1);
Collections.sort(gameBeans, new GameComparator(SORT_TIME_VALUE, 1));
for (GameBean gameBean : gameBeans) {
System.out.println(gameBean.getTime());
}
}
private static void add(String time, int count) {
for (int i = 0; i < count; i++) {
GameBean gameBean0 = new GameBean();
gameBean0.setTime(time);
gameBean0.setPrice(time);
gameBeans.add(gameBean0);
}
}
static class GameComparator implements Comparator<GameBean> {
String mSortField;
int mSortType;// 1:升序 -1:降序
public GameComparator(String sortField) {
this(sortField, 1);
}
public GameComparator(String sortField, int sortType) {
this.mSortField = sortField;
this.mSortType = sortType;
}
@Override
public int compare(GameBean lhs, GameBean rhs) {
int ret = 0;
if (SORT_TIME_VALUE.equals(mSortField)) {
Long x = Long.valueOf(lhs.getTime());
Long y = Long.valueOf(rhs.getTime());
ret = mSortType * x.compareTo(y);
} else if (PRICE_DOLLAR.equals(mSortField)) {
Float x = Float.valueOf(lhs.getPrice());
Float y = Float.valueOf(rhs.getPrice());
ret = mSortType * x.compareTo(y);
}
return ret;
// return (Integer.valueOf(lhs.getTime()) > Integer.valueOf(rhs.getTime())) ? 1 : -1;
}
}
static class GameBean {
private String time;
private String price;
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getPrice() {
return price;
}
public void setPrice(String price) {
this.price = price;
}
}
}
注意:
- 不要用三目運算子返回. o1 > o2 ? 1 : -1沒有考慮相等的情況,如果o1等於o2就違背了3條原則。
- 不要將long強轉成int. 如果long超過了int最大值會導致資料錯誤,進而影響排序。
- 不要忽略比較的傳遞性. 尤其是比較邏輯很複雜時。
想了解更多,可以看一下下面幾篇文章:
相關推薦
Collections.sort()崩潰分析
對List排序一般採用兩種方法: (1)實體類實現Comparable<T>介面,完成compareTo(T o)方法。 (2)建立一個Comparator<T>的實現類,完
jdk7 Collections.sort()方法報錯分析
問題背景 起因 前些天測試給提了一個專案裡的bug,在檢視專案的一個線上資料的列表的時候發生了崩潰.然後我根據bugly定位發現是在使用Collection.sort()對list排序的時候產生Comparison method violates its general cont
windowsclient崩潰分析和調試
而在 ros lag this指向 eas 位置 call 即使 多個實例 本文介紹windows上崩潰分析的一些手段,順便提多進程調試、死鎖等。 1.崩潰分析過程 1.1 確認錯誤碼 不管是用windbg還是用vs。首先應該註意的是錯誤碼,而90%以上的崩潰都是非法
Collections.sort詳解
排序。 根據 強行 strong null equals() cti ron 順序 Collections.sort(list, new PriceComparator());的第二個參數返回一個int型的值,就相當於一個標誌,告訴sort方法按什麽順序來對list進行排序
java中Collections.sort排序詳解
比較器 元素 .net 字符 atp style pri com 實現接口 Comparator是個接口,可重寫compare()及equals()這兩個方法,用於比價功能;如果是null的話,就是使用元素的默認順序,如a,b,c,d,e,f,g,就是a,b,c,d,e,f
java基礎——Collections.sort的兩種用法
基本類 == 輸出結果 code sed java 意思 size htm Collections是一個工具類,sort是其中的靜態方法,是用來對List類型進行排序的,它有兩種參數形式: public static <T extends Comparabl
java Collections.sort()實現List排序的默認方法和自定義方法
public get object 順序 text main 輸出 any 比較 1.java提供的默認list排序方法 主要代碼: List<String> list = new ArrayList();list.add("劉媛媛"); list.add("王
Hadoop自帶Sort例子分析
lan exit more double expr ogr oms lru sort /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor lic
collections.sort對javabean的list進行排序
collection.sort javabean 1、collection.sort排序算法底層實際是 將集合轉換成array,再執行arrays.sort,arrays.sort利用歸並排序,優化的快排,timSort等方式。2、對string類型數據排序public static void col
04-java.util.Collections+Collections.sort()方法的練習
1、java.util.Collections:集合框架的工具類,裡面的方法都是靜態方法。此類完全由在collection上進行操作或返回collection的靜態方法組成。如果為此類的方法所提供的collection或類物件為null,則這些方法都將丟擲NullPointerException
Java的陣列和list升序,降序,逆序函式Collections.sort和Arrays.sort的使用
list升序,降序,逆序List<Integer>list =new ArrayList<Integer>();//如果list是 5 7 2 6 8 1 41、升序:Collections.sort(list) //list: 1 2 4 5 6 7 82、降序:Collection
android Collections.sort排序的一種使用
//按照javabean的時間排序 Collections.sort(infosList, new Comparator<Dzbp_Info>() { @Override public int compare(Dzbp_Info lhs, Dzbp_Info rhs)
關於集合迭代器以及Collections.sort(元素)的一點事
/*一般Collections.sort()用來排序泛型為Integer的集合,若要排序其他型別,必須要 讓該類實現Comparable<T>介面 */ public class day implements Comparable<day> { private in
collections.sort()預設排序規則
預設按ASCII碼排序,一位一位的比較,應該排了3次 第一次比較第一位全部是a,所以順序沒變 第二次第二位排序[a0, a1, a12, a11, a10, a2, a3, a4, a5, a6, a7, a8, a9] 第三次第三位排序[a0, a1, a10, a11, a12, a2, a
List排序Collections.sort 重寫compare
1 static List<Integer> intList = Arrays.asList(2,5,7, 3, 1); 2 3 public static void main(String[] args) { 4 5
實現List集合排序的兩種方法(使用Collections.sort方法)
1:實現comparable package core.java.collection.collections; public class User implements Comparable<User>{ private i
Java中Collections.sort()的使用
在日常開發中,很多時候都需要對一些資料進行排序的操作。然而那些資料一般都是放在一個集合中如:Map ,Set ,List 等集合中。他們都提共了一個排序方法 sort(),要對資料排序直接使用這個方法就行,但是要保證集合中的物件是 可比較的。 怎麼讓一個物件是
Collections.sort()方法和lambda表示式結合實現集合的排序
1.使用Collections.sort()實現集合的排序,這裡的方法具體指的是: Collections.sort(List list, Compatator c) 第一個引數:為要進行排序的集合。 第二個引數:Compatator的實現,指定排序的方式。 2
JAVA Collections.sort方法在SSH三大框架中使用中的問題
最近,一同學在開發中遇到了SSH三大框架中使用到了Collections.sort方法。然而,他開發環境中的JDK 是1.7.0_64,網站部署的JDK版本是1.7.0_80,他通過開發環境中產生的.class直接去更新網站部署環境中的.class 檔案後,程式
Collections.sort的兩種用法
Collections是一個工具類,sort是其中的靜態方法,是用來對List型別進行排序的,它有兩種引數形式: public static <T extends Comparable<? super T>> void sort(List