2012-11-22 41 views
9

它已被問過,但我還沒有找到一個體面的實現與解釋。Java:null安全的compareTo方法

public int compareTo(Object o) 
{ 
    if (this == null || o == null) 
    { 
     return 0; 
    } 
    Tok tmp = (Tok) o;  
    if (this.rang < tmp.rang) 
    { 
     return -1; 
    } else if (this.rang > tmp.rang) { 
     return 1; 
    } else { 
     return 0; 
    } 
} 

我讀了兩個類似的問題,我找到了;他們堅持實施另一種方法。我不明白爲什麼這不應該起作用。該方法獲取一個額外的對象,並檢查它是否有效的實例或null,如果null只是簡單地返回0;什麼是最簡單的方法來實現無效安全compareTo

爲我工作的實施是:

public int compareTo(Object o) 
{ 
    if (o == null) 
    { 
     return 0; 
    } 
    Tok tmp = (Tok) o;  
    if (this.rang < tmp.rang) 
    { 
     return -1; 
    } else if (this.rang > tmp.rang) { 
     return 1; 
    } else { 
     return 0; 
    } 
} 

這不是最佳的實現應該在看什麼位置貼好人民的答案。對於我的特殊情況,這足夠體面,因爲它永遠不會爲空,但收到的對象可以爲null,並且初始實現狀態(如果其中任何一個爲null)返回0.所以,如果給定對象爲null,則返回0。

+12

在Java中,'this'是**從不** **'null'。 –

+0

@MattBall他可能是指** this.someInstance ** – PermGenError

+0

這永遠不能爲空 –

回答

12

就我個人而言,我喜歡Guava's Ordering進行無效比較。您可以指定#nullsFirst()#nullsLast()以避免NullPointerException s。

其他重要事項,大多來自評論:

  • this在Java中從未null
  • 考慮使用Guava's ComparisonChain如果你正在實施細粒度compareTo()
  • 在實施Comparable ,請務必指定類型參數,以便獲得編譯時類型安全性,而不必使用instanceof或強制轉換:

    class Tok implements Comparable<Tok> { 
        // snip 
    
        public int compareTo(Tok other) { 
         // snip 
        } 
    } 
    
5

返回0意味着thiso是相等的,如果o爲空,則不是這樣。而且,this永遠不會爲空。

當然,這取決於應用程序。你可能想要一個應該等於null的對象。您返回的內容取決於您,但是如果您正在尋找一種通用的無效安全方法,它並不是很理想。

要完全通用,我會檢查o是否爲null,如果是,則拋出某種異常。

+1

根據Comparable的文檔,具體爲NullPointerException。 http://docs.oracle.com/javase/6/docs/api/java/lang/Comparable.html – DPM

+0

我不需要例外我有一個Tok []對象的數組,我把它給Arrays.sort()和我獲得Null異常。 –

+0

Emmerioch是對的,請相信我們,不要空值檢查,看到我的答案在下面,但讓你的代碼乾淨,刪除或避免你想要排序的Tok []中的空對象!去幹淨的方式,否則你花費很多時間搜索一個bug,你很可能找不到容易的東西。 – AlexWien

1

比較兩個對象可以爲空,安全的,因爲任何其它方法,這裏的缺點是,通常的方法有兩個參數,但compareTo接收一個和另一個是對象本身。

this永遠不能爲null,這將意味着你正在執行代碼在null對象(無實例)。在這種情況下,NullPointerException將在compareTo的調用時被拋出,從而無法執行其代碼。

與對象一樣有許多方法,因爲比較可以基於可爲空的類的字段(旨在排除基本類型的預期上限)。因此,長話短說,您的空檢查應涵蓋您在compareTo和使用的字段中作爲參數收到的對象。另外,如果你有一個包含某些邏輯的外部實例(即一個實用程序類),你應該檢查該實例是否也爲空。

作爲一個附註,如果涉及的任何對象是null必須是一致的並且有文件記錄(您可以返回-1或1,以便在開頭或結尾放置空值)。只是避免返回0(這將是相同的情況下,如果equalsnull對象返回true

1

奇怪,因爲它看起來卻並不安全。請儘量把托克添加到TreeSet的或TreeMap的(作爲鍵)你會得到一個NullPointerException。問題是TreeSet插入是基於TreeMap的,當你嘗試添加(null)底層映射時,會嘗試把你的空值導致NPE

+0

誰說OP使用'TreeSet'或'TreeMap'? –

+0

@matt OP在他的一個評論中說,他使用了使用compateTo()的sort()。 – AlexWien

+0

@AlexWien ...它特別暗示OP不是使用'TreeSet'或'TreeMap'。 –

4

我不滿足於其他答案:
你不應該在compareTo中檢查null。
它被要求拋出一個NullPointerException,否則你會亂七八糟樹起你的樹並且難以找到爲什麼你的TreeMap不起作用。

一個非常值得推薦的方法:

public int compareTo(Tok other) { 
    int thisRang = this.rang; 
    int otherRang = other.rang; 
    return (thisRang < otherRang ? -1 : (thisRang == otherRang ? 0 : 1)); 
    } 
    public int compareTo(Object other) { 
    return compareTo((Tok)other); 
    } 

而且做到盡善盡美類托克應該是最後! (否則,你可能有問題 當你從托克。子類(孫作出錯誤等級日期)

final class Tok { 
    int rang; 
} 

與比較處理,等於沒有那麼容易,可以考慮使用樹木,而不是(TreeMap的)一個HashMap,那麼你沒有實現的compareTo。 你應該實現的hashCode,在那裏你只需返回this.rang。

最後它是高度recomended,但並不強制要求實現equals()

public boolean equals(Object obj) { 
return obj instanceof Tok 
    && this.rang() == ((Tok) obj).rang; 
} 
+0

將Tok對象數組放入Arrays.sort(tok [])仍然會產生異常。 –

+0

是哪個例外?空指針?這很好!你的Tok []中不應該有一個空對象。請務必不添加null對象到你的Tok [] – AlexWien

+0

但是這是一個問題,我知道我可以縮短我的Tok []不包含任何空索引但是這意味着我需要創建另一個數組非空索引,然後複製這個數組放入一個臨時數組並對其進行排序。它只是爲了複雜,我只是想把所有的null元素放在bigest上,並把它們放在最後。 –

1

的AUT hor堅稱他不想從他的 Tok []中刪除空值。
這裏是一個soultion允許與NULL值進行排序,並沒有違反Java的合同

爲了避免這種情況,您創建類托克內的compareTo違反了的compareTo合同, 您創建一個明確的NullSafeComparator:

/** 
* This comparator accepts null objects, 
* sorts ascending, null values are after non null values. 
*/ 
public static final class NullSafeComparator implements Comparator<Tok> { 
    public int compare(Tok o1, Tok o2) { 
     int r1 = Integer.MAX_VALUE; 
     int r2 = Integer.MAX_VALUE; 
     if (o1 != null) { 
      r1 = o1.rang; 
     } 
     if (o2 != null) { 
      r2 = o2.rang; 
     } 
     return (r1 < r2 ? -1 : (r1 == r2 ? 0 : 1)); 
    } 
} 

簡化類鐸(除去其用於定義static關鍵字的所有內的一個單元測試類):

public static class Tok { 
    int rang; 
    public Tok(int rang) { 
     this.rang = rang; 
    } 
    public String toString() { 
     return Integer.toString(rang); 
    } 
} 

最後一個未它測試表明:

public void testSort() { 

    Tok[] toks = new Tok[5]; 
    toks[0] = new Tok(3); 
    toks[1] = new Tok(1); 
    toks[2] = null; 
    toks[3] = null; 
    toks[4] = new Tok(2); 



    Arrays.sort(toks, new NullSafeComparator()); 



    for (Tok tok: toks) { 
     System.out.println(tok); 
    } 
    assertEquals(1, toks[0]); 
    assertNull(toks[4]); 
} 

這將給以下期望的結果:

1 
2 
3 
null 
null 
+2

放鬆一下。 「比較器」可以是無效的; [JavaDoc明確地這麼說](http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html):_「與」Comparable「不同,比較器可以選擇性地允許比較null參數,同時保持對等效關係的要求。「_ –

+0

好的,我將從代碼中刪除Dirty – AlexWien

0

按照documentation

Note that null is not an instance of any class, and e.compareTo(null) should 
throw a NullPointerException even though e.equals(null) returns false. 

所以,如果你實現一個空安全的方法,其行爲將會是意料之外的(也可能與文檔無關,並且與API的其他部分進行合作)。