處理 Comparable介面不嚴謹導致Comparison method violates its general contract!
阿新 • • 發佈:2019-01-09
本文主旨是記錄問題解決過程
出錯的日誌
Shutting down VM
--------- beginning of crash
FATAL EXCEPTION: main
Process: com.gezbox.deliver, PID: 25572
java.lang.IllegalArgumentException: Comparison method violates its general contract!
AndroidRuntime: at java.util.TimSort.mergeLo(TimSort.java:773)
AndroidRuntime: at java.util.TimSort.mergeAt(TimSort.java:510)
AndroidRuntime: at java.util.TimSort.mergeForceCollapse(TimSort.java:453)
AndroidRuntime: at java.util.TimSort.sort(TimSort.java:250)
AndroidRuntime: at java.util.Arrays.sort(Arrays.java:1523)
AndroidRuntime: at java.util.Collections.sort (Collections.java:238)
AndroidRuntime: at com.zzz.XXXFragment.refreshDate(XXXFragment.java:203)
AndroidRuntime: at com.zzz.XXXFragment$2.onSuccess(XXXFragment.java:152)
AndroidRuntime: at com.zzz.XXXFragment$2.onSuccess(XXXFragment.java:147)
AndroidRuntime: at com.gezbox.net.Callback.onResponse (Callback.java:79)
AndroidRuntime: at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:70)
AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:754)
AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95)
AndroidRuntime: at android.os.Looper.loop(Looper.java:165)
AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6365)
AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:883)
AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
原因
- JDK7中的Collections.Sort方法實現中,你的返回值需要嚴謹全面;
- 如果兩個值是相等的,那麼compare方法需要返回0,否則 可能 會在排序時拋錯,而JDK6是沒有這個限制的。
- 在在 JDK7 版本以上,Comparator 要滿足自反性,傳遞性,對稱性
程式碼使用的範例
說明:
1) 自反性:x,y 的比較結果和 y,x 的比較結果相反。
2) 傳遞性:x>y,y>z,則 x>z。
3) 對稱性:x=y,則 x,z 比較結果和 y,z 比較結果相同
對比程式碼一般是這樣的結構,寫一段放著看看
Collections.sort(dataList, new Comparator<PackageInfo>() {
@Override
public int compare(PackageInfo item1, PackageInfo item2) {
return xxxxx.compare(xxxxx);
}
});
有個簡單的解決辦法
- 找出所有的條件語句
- 針對所有條件,列出所有的可能情況。然後遍歷一遍,覆蓋所有的路徑
上程式碼
範例
Collections.sort(dataList, new Comparator<ProcessingOrderResponse.PackageInfo>() {
@Override
public int compare(ProcessingOrderResponse.PackageInfo item1, ProcessingOrderResponse.PackageInfo item2) {
if (TextUtils.equals(mContext.getResources().getString(R.string.task_order_return), item1.packageNo)) {
return 1;
} else if (TextUtils.equals(mContext.getResources().getString(R.string.task_order_return), item2.packageNo)) {
return -1;
} else {
return item1.packageNo.compareTo(item2.packageNo);
}
}
});
修改後的
Collections.sort(dataList, new Comparator<ProcessingOrderResponse.PackageInfo>() {
@Override
public int compare(ProcessingOrderResponse.PackageInfo item1, ProcessingOrderResponse.PackageInfo item2) {
if (TextUtils.equals(mContext.getString(R.string.task_order_return), item1.packageNo)
&& TextUtils.equals(mContext.getString(R.string.task_order_return), item2.packageNo)) {
return 0;
} else if (!TextUtils.equals(mContext.getString(R.string.task_order_return), item1.packageNo)
&& TextUtils.equals(mContext.getString(R.string.task_order_return), item2.packageNo)) {
return 1;
} else if (TextUtils.equals(mContext.getString(R.string.task_order_return), item1.packageNo)
&& !TextUtils.equals(mContext.getString(R.string.task_order_return), item2.packageNo)) {
return -1;
} else {
if (item1.packageNo.compareTo(item2.packageNo) > 0) {
return 1;
} else if (item1.packageNo.compareTo(item2.packageNo) == 0) {
return 0;
} else {
return -1;
}
}
}
});
簡單說明
這裡有三個判斷條件
兩個TextUtil.equals 以及String.compareTo
解決思路是
想講兩個TextUtil.equals這的所有路徑都遍歷,得到4個狀態,分別給出1,0,-1這幾個返回值
剩下的String.compareTo也遍歷一遍,給出1,0,-1三個返回值
網上找了一圈,本來想看看java的原始碼,結果。。。。沒找到原始碼,有知道的朋友麻煩告訴我一下,在此先謝過