2017-09-24 69 views
-1

我搜索了一些相同的問題,我知道原因。然而,碰撞發生的只有一次,所以我來這裏問你什麼可能導致崩潰。」比較方法違反了它的一般合同!「

Collections.sort(downloadTasks, new Comparator<DownloadTask>() { 
     @Override 
     public int compare(DownloadTask lhs, DownloadTask rhs) { 
      if (lhs == null || rhs == null) return 0; 
      return (int) (lhs.mTaskInfo.time - rhs.mTaskInfo.time); 
     } 
    }); 

的錯誤是:

java.lang.IllegalArgumentException異常:比較法違反其總承包!在java.util.TimSort.mergeHi(TimSort.java:864) at java.util.TimSort.mergeAt(TimSort.java:481) at java.util.TimSort.mergeCollapse(TimSort.java:406) at java .util.TimSort.sort(TimSort.java:210) at java.util.TimSort.sort(TimSort.java:169) at java.util.Arrays.sort(Arrays.java:2010) at java.util .Collections.sort(Collections.java:1883)

正如你所看到的,我通過它們的time成員比較兩個對象。 timelong類型。

我認爲墜機可能是從:

  • 是否也將長期爲int導致崩潰?
  • if(lhs == null || rhs == null)return 0;但理論上lhs和rhs都不爲零。

編輯

如果lhsrhs可以爲空,我該怎麼辦?

EDIT對於Android的

在Android中,Long.compare()需要API 19.您可以在API 19做到這一點:

public static int compare(long lhs, long rhs) { 
    return lhs < rhs ? -1 : (lhs == rhs ? 0 : 1); 
} 
+0

什麼會崩潰嗎?你會得到什麼樣的錯誤,什麼時候,什麼代碼,會發生什麼,你期望會發生什麼?看看[問] – pvg

+0

由於標題說錯誤是'比較方法違反其總合約!' – CoXier

+0

你能解釋爲什麼演員導致崩潰? @Thilo – CoXier

回答

4

這兩種情況下是有問題的。

if (lhs == null || rhs == null) return 0;

如果你有[123, null, 234],那麼你比較123爲等於nullnull爲等於234,並傳遞你應該得到123等於234。但這不是你的比較器返回的結果。

這裏的解決辦法是要麼不允許null或排序的所有nulls的底部(或頂部),即只返回0null,否則返回1-1(取決於null正在向左或向右)。

return(int)(lhs.mTaskInfo.time - rhs.mTaskInfo。時間);

考慮比較Integer.MAX_VALUE + 10。兩者的區別是Integer.MAX_VALUE + 1。將其轉換爲int包裝爲Integer.MIN_VALUE。然後相反的比較應該給你- Integer.MIN_VALUE,但是that is Integer.MIN_VALUE again due to overflow

這裏的解決方案是使用Long.compare(a,b)

1

比較法的「總承包」是有據可查的compare(T o1, T o2)方法的Javadoc:

實現程序必須確保sgn(compare(x, y)) == -sgn(compare(y, x))所有xy。 (這意味着compare(x, y)必須拋出當且僅當compare(y, x)拋出異常的異常。)

實現類還必須確保關係是可傳遞:((compare(x, y)>0) && (compare(y, z)>0))意味着compare(x, z)>0

最後,實現者必須確保compare(x, y)==0暗示sgn(compare(x, z))==sgn(compare(y, z))適用於所有z。

那麼,您違反了這3條規則中的哪一條? 所有3

第一條規則被違反,因爲timelong,所以(int) (lhs.mTaskInfo.time - rhs.mTaskInfo.time)可以等於Integer.MIN_VALUE。如果將兩個參數翻轉到compare(),結果仍然是Integer.MIN_VALUE,因爲int值不能存儲取反的值。

第二條規則被違反,因爲int溢出。由於timelong,我假設它們包含標準的毫秒值,並且int只能存儲值高達24天。所以我們假設輸入是Jan 1, Jan 15, Jan 30compare(Jan 1, Jan 15)是+14天,而compare(Jan 15, Jan 30)是+15天,但compare(Jan 1, Jan 30)應該是+29天,但它溢出的回報大概是-19天。哎呀!!!!

由於錯誤的空檢查,第三條規則被違反。假設輸入是null, Jan 1, Jan 2compare(null, Jan 1)爲0,所以是compare(null, Jan 2),但compare(Jan 1, Jan 2)是+1天。

int溢出和MIN_VALUE問題可以很容易地通過使用Long.compare(long x, long y)固定。

對於null問題,您需要確定空值是否應該先排序或最後排序。下面將第一排序空值:

public int compare(DownloadTask lhs, DownloadTask rhs) { 
    if (lhs == null) { 
     if (rhs == null) 
      return 0; 
     return -1; 
    } 
    if (rhs == null) 
     return 1; 
    return Long.compare(lhs.mTaskInfo.time, rhs.mTaskInfo.time); 
} 

或者單報表版本:

public int compare(DownloadTask lhs, DownloadTask rhs) { 
    return (lhs == null ? (rhs == null ? 0 : -1) 
      : (rhs == null ? 1 : Long.compare(lhs.mTaskInfo.time, rhs.mTaskInfo.time))); 
} 
+0

真棒和清晰的答案。非常感謝。 – CoXier

相關問題