1. 程式人生 > >處理 Comparable介面不嚴謹導致Comparison method violates its general contract!

處理 Comparable介面不嚴謹導致Comparison method violates its general contract!

本文主旨是記錄問題解決過程

出錯的日誌

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個狀態,分別給出10,-1這幾個返回值
剩下的String.compareTo也遍歷一遍,給出10,-1三個返回值

網上找了一圈,本來想看看java的原始碼,結果。。。。沒找到原始碼,有知道的朋友麻煩告訴我一下,在此先謝過