欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

java中排序報:Comparison method violates its general contract異常的解決

 更新時間:2017年06月19日 09:25:16   作者:Pulpcode  
這篇文章主要給大家介紹了關(guān)于java中排序報:Comparison method violates its general contract異常的解決方法,文中介紹的非常詳細(xì),對大家具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起看看吧。

前言

上周線上的一段排序的java代碼出現(xiàn)了一個Comparison method violates its general contract,在解決這個問題的途中學(xué)到了一些知識這里總結(jié)分享一下。

異常原因

這個排序?qū)е碌漠惓趈ava7以上的版本出現(xiàn),所以如果你的JDK從6升級到了7或者8,那一定要小心此異常。

在java7的兼容列表中,就有對此排序不兼容的說明:

Area: API: Utilities
Synopsis: Updated sort behavior for Arrays and Collections may throw an IllegalArgumentException
Description: The sorting algorithm used by java.util.Arrays.sort and (indirectly) by java.util.Collections.sort has been replaced. The new sort implementation may throw an IllegalArgumentException if it detects a Comparable that violates the Comparable contract. The previous implementation silently ignored such a situation.
If the previous behavior is desired, you can use the new system property, java.util.Arrays.useLegacyMergeSort, to restore previous mergesort behavior.
Nature of Incompatibility: behavioral
RFE: 6804124

我從資料中查閱到j(luò)ava7開始引入了Timsort的排序算法。我之前一直以為大部分標(biāo)準(zhǔn)庫的內(nèi)置排序算法都是快速排序。現(xiàn)在才得知很多語言內(nèi)部都使用Timsort排序。隨后我在wiki百科上找到了這樣一句話:

t was implemented by Tim Peters in 2002 for use in the Python programming language.

所以這個排序自然是以他命名的。

隨后我又在網(wǎng)上找到了這樣一張圖排序比較的圖:

可以發(fā)現(xiàn),Timsort在表現(xiàn)上比QuickSort還要好。

這篇博客不去詳細(xì)討論Timsort的實(shí)現(xiàn)(看上去這個算法還挺復(fù)雜的),我可能會寫另一篇博客單獨(dú)討論Timsort,簡單來說Timsort結(jié)合了歸并排序和插入排序。這個算法在實(shí)現(xiàn)過程中明確需要:嚴(yán)格的單調(diào)遞增或者遞減來保證算法的穩(wěn)定性。

  • sgn(compare(x, y)) == -sgn(compare(y, x))
  • ((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0
  • compare(x, y)==0 implies that sgn(compare(x, z))==sgn(compare(y, z)) for all z

看上去很像離散數(shù)學(xué)課中學(xué)習(xí)的集合的對稱性,傳遞性的關(guān)系。

所以異常的原因是因?yàn)榕判蛩惴ú粔驀?yán)謹(jǐn)導(dǎo)致的,實(shí)際上業(yè)務(wù)上的代碼經(jīng)常不如純技術(shù)上的嚴(yán)謹(jǐn)。比如對于這樣一個算法:

選出航班中的最低價

那如果兩個相等低價同時存在,按照尋找最低價的邏輯如果這么寫:

if (thisPrice < lowPrice){
 lowPrice = thisPrice;
}

那低價這個位置就是“先到先得”了。

但如果這么實(shí)現(xiàn):

if(thisPrice <= lowPrice){
 lowPrice = thisPrice;
}

那后面的低價就會覆蓋前面的,變成了“后來者居上”。編程中經(jīng)常遇到先到先得和后來者居上這兩個問題。

所以對于上面那個需要提供嚴(yán)謹(jǐn)?shù)呐袛啻笮”容^函數(shù)實(shí)現(xiàn)。所以如果是這樣的:

return x > y ? 1 : -1;

那么就不符合此條件。

不過我們邏輯要比這個復(fù)雜,其實(shí)是這樣一個排序條件。按照:

  • 價格進(jìn)行排序,如果價格相等則起飛時間靠前的先排。
  • 如果起飛時間也相等,就會按照:
  • 非共享非經(jīng)停>非經(jīng)停>非共享>經(jīng)停的屬性進(jìn)行優(yōu)先級選擇,如果這些屬性都全部相等,才只能算是相等了。

所以這個判斷函數(shù)的問題是:

public compareFlightPrice(flightPrice o1, flightPrice o2){
 // 非經(jīng)停非共享
 if (o1.getStopNumber() == 0 && !o1.isShare()) {
 return -1;
 } else if (o2.getStopNumber() == 0 && !o2.isShare()) {
 return 1;
 } else {
 if (o1.getStopNumber() == 0) {
  return -1;
 } else if (o2.getStopNumber() == 0) {
  return 1;
 } else {
  if (!o1.isShare()) {
  return -1;
  } else if (!o2.isShare()) {
  return 1;
  } else {
  if (o1.getStopNumber() > 0) {
   return -1;
  } else if (o2.getStopNumber() > 0) {
   return 1;
  } else {
   return 0;
  }
  }
 }
 }
}

這個函數(shù)有明顯的先到先得的問題,比如對于compareFlightPrice(a, b) ,如果ab都是非共享非經(jīng)停,那么這個就會把a(bǔ)排到前面,但如果調(diào)用compareFlightPrice(b, a) ,b又會排到前面,所以必須判斷a是非共享非經(jīng)停且b不是非共享非經(jīng)停,才能讓a排在前面。

當(dāng)然除了改比較函數(shù),還有一個解決方式是:給jvm添加啟動參數(shù)。

-Djava.util.Arrays.useLegacyMergeSort=true

還需要注意的是,并不一定你的集合中存在相等的元素,并且比較函數(shù)不符合上面的嚴(yán)謹(jǐn)定義,就一定會穩(wěn)定浮現(xiàn)此異常,實(shí)際上我們在生產(chǎn)環(huán)境出現(xiàn)此異常的概率很小,畢竟java并不會蠢到先去把整個數(shù)組都校驗(yàn)一遍,實(shí)際上它是在排序的過程中發(fā)現(xiàn)你不符合此條件的。所以有可能某種集合順序讓你剛好繞過了此判斷。

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • springboot vue完成發(fā)送接口請求顯示響應(yīng)頭信息

    springboot vue完成發(fā)送接口請求顯示響應(yīng)頭信息

    這篇文章主要為大家介紹了springboot+vue完成發(fā)送接口請求顯示響應(yīng)頭信息,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • 詳解JavaWeb中的 Listener

    詳解JavaWeb中的 Listener

    JavaWeb里面的listener是通過觀察者設(shè)計模式進(jìn)行實(shí)現(xiàn)的。下面通過本文給大家詳細(xì)介紹javaweb中的listener,感興趣的朋友一起看看吧
    2016-09-09
  • Java實(shí)現(xiàn)抽獎算法的示例代碼

    Java實(shí)現(xiàn)抽獎算法的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用Java語言實(shí)現(xiàn)抽獎算法,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Java有一定幫助,需要的可以參考一下
    2022-04-04
  • SpringBoot+MyBatisPlus對Map中Date格式轉(zhuǎn)換處理的方法詳解

    SpringBoot+MyBatisPlus對Map中Date格式轉(zhuǎn)換處理的方法詳解

    在?SpringBoot?項目中,?如何統(tǒng)一?JSON?格式化中的日期格式。本文將為大家介紹一種方法:利用MyBatisPlus實(shí)現(xiàn)對Map中Date格式轉(zhuǎn)換處理,需要的可以參考一下
    2022-10-10
  • Java?Chassis3熔斷機(jī)制的改進(jìn)路程技術(shù)解密

    Java?Chassis3熔斷機(jī)制的改進(jìn)路程技術(shù)解密

    這篇文章主要介紹了Java?Chassis?3技術(shù)解密之熔斷機(jī)制的改進(jìn)路程實(shí)例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • SpringBoot整合mybatis/mybatis-plus實(shí)現(xiàn)數(shù)據(jù)持久化的操作

    SpringBoot整合mybatis/mybatis-plus實(shí)現(xiàn)數(shù)據(jù)持久化的操作

    這篇文章主要介紹了SpringBoot整合mybatis/mybatis-plus實(shí)現(xiàn)數(shù)據(jù)持久化,本節(jié)內(nèi)容我們介紹了數(shù)據(jù)持久化的相關(guān)操作,并且是基礎(chǔ)傳統(tǒng)的關(guān)系型數(shù)據(jù)庫——mysql,需要的朋友可以參考下
    2022-10-10
  • Spring boot 基本部署方式

    Spring boot 基本部署方式

    SpringBoot部署也是非常簡單,需要把打包輸出的包由jar改為war。具體部署方式大家參考下本文
    2017-08-08
  • java實(shí)現(xiàn)遺傳算法實(shí)例分享(打印城市信息)

    java實(shí)現(xiàn)遺傳算法實(shí)例分享(打印城市信息)

    本文介紹java實(shí)現(xiàn)遺傳算法的實(shí)例,代碼中使用城市名做為數(shù)據(jù),可以打印當(dāng)前代數(shù)的所有城市序列,以及其相關(guān)的參數(shù),大家參考使用吧
    2014-01-01
  • Java contains用法示例

    Java contains用法示例

    這篇文章主要介紹了Java contains的用法示例,幫助大家更好的理解和學(xué)習(xí)Java,感興趣的朋友可以了解下
    2020-11-11
  • Java定時任務(wù)實(shí)現(xiàn)優(yōu)惠碼的示例代碼

    Java定時任務(wù)實(shí)現(xiàn)優(yōu)惠碼的示例代碼

    在Java中實(shí)現(xiàn)定時任務(wù)來發(fā)放優(yōu)惠碼,我們可以使用多種方法,比如使用java.util.Timer類、ScheduledExecutorService接口,或者更高級的框架如Spring的@Scheduled注解,這篇文章主要介紹了Java定時任務(wù)實(shí)現(xiàn)優(yōu)惠碼的實(shí)例,需要的朋友可以參考下
    2024-07-07

最新評論