2015-07-21 91 views
1

我知道很多答案都回答了我的問題。在我的代碼,除了表示「比較法違反其總承包」,但我不知道我的比較方法是如何違反其一般contract.This是我的代碼:比較方法違反了它的一般合同java7

public static List<Entry<Integer, Double>> sortMap(
    Map<Integer, Double> curMap, final boolean isDesc) { 
    List<Entry<Integer, Double>> res = new ArrayList<Entry<Integer, Double>>(); 
    for (Entry<Integer, Double> iter : curMap.entrySet()) { 
     res.add(iter); 
    } 
    Collections.sort(res, new Comparator<Entry<Integer, Double>>() { 
     public int compare(Entry<Integer, Double> o1, 
       Entry<Integer, Double> o2) { 
      if (o1.getValue() == o2.getValue()) { 
       return 0; 
      } else if (o1.getValue() > o2.getValue()) { 
       return isDesc ? -1 : 1; 
      } 
      return isDesc ? 1 : -1; 
     } 
    }); 
    return res; 
} 

回答

2

有幾個微妙的東西去在這。這不是Stack Overflow上其他地方常見的「破碎比較器」問題。雖然這個比較器確實壞了,但很難看到。

第一個問題是比較器主要負責比較Double值,即盒裝double的值。鑑於>操作員將執行自動取消裝箱操作並對所包含的值進行數字比較,==操作員將測試參考相等性。一般而言,

Double.valueOf(1.23) == Double.valueOf(1.23) // WARNING: reference comparison, not numeric! 

將是false。如果你真的想測試Double值的數值相等,你必須做

if (o1.getValue().doubleValue() == o2.getValue.doubleValue()) ... 

這主要是工作,如果您輸入只包含實際數值。不過,我懷疑你的輸入包含NaN值,這些值具有模糊(甚至無意義)的行爲。特別是,將NaN與任何數值比較都是錯誤的,並且NaN比較不等於自身!這違反了關於數字比較的各種規則;事實上,NaN就實數而言是無序的。這就是排序算法遇到NaN值時中斷的原因。

NaN是除以0.0通過0.0,除其他事項外的結果。)

有一種方法Double.compare(double d1, double d2),處理NaN合理;它將NaN的值整理爲Double.POSITIVE_INFINITY以上。 (這也區別於負零正零,但是這不太可能造成你的問題。)有一個伴隨方法Double.compareTo(Double)相比之下盒裝Double值。

我已經重寫你的比較是這樣的:

Collections.sort(res, new Comparator<Entry<Integer, Double>>() { 
    public int compare(Entry<Integer, Double> o1, 
         Entry<Integer, Double> o2) { 
     if (isDesc) { 
      return o2.getValue().compareTo(o1); 
     } else { 
      return o1.getValue().compareTo(o2); 
     } 
    } 
} 

由於DoubleComparable本身,在Java中8,你可以通過避免使用工具方法上Map.Entry編寫自己的比較。您也可以使用Listsort()默認的方法,這將是在一般的速度更快:

if (isDesc) { 
    res.sort(Map.Entry.<Integer,Double>comparingByValue().reversed()); 
} else { 
    res.sort(Map.Entry.comparingByValue()); 
} 

(不幸的是,類型推理完全不是那麼回事,所以你必須以獲得提供「型證人」 )

最後,您可以使用「菱形」運算符和ArrayList拷貝構造函數更加簡潔地複製映射條目。重寫的程序是這樣的:

public static List<Entry<Integer, Double>> sortMap(
     Map<Integer, Double> curMap, final boolean isDesc) { 
    List<Entry<Integer, Double>> res = new ArrayList<>(curMap.entrySet()); 

    if (isDesc) { 
     res.sort(Map.Entry.<Integer,Double>comparingByValue().reversed()); 
    } else { 
     res.sort(Map.Entry.comparingByValue()); 
    } 

    return res; 
} 
相關問題