9

以前にも質問されましたが、説明のある適切な実装が見つかりませんでした。

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;
    }
}

私はまだ見つけた 2 つの同様の質問を読みました。彼らは別の方法を実装することを主張します。これが機能しない理由がわかりません。メソッドは追加のオブジェクトを取得し、それが有効なインスタンスかどうかをチェックnullnullます0。null-safe を実装する最も簡単な方法は何でしょう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になる可能性があり、どちらかがnullの場合は0を返す初期実装状態であるため、これで十分でした。したがって、指定されたオブジェクトがnullの場合は0が返されます。

4

7 に答える 7

12

個人的には、null セーフの比較にはGuavaが気に入っています。Orderingsを指定し#nullsFirst()たり#nullsLast()、回避したりできますNullPointerException

主にコメントからのその他の重要なメモ:

  • thisJavaには決してありません null
  • きめComparisonChain細かいcompareTo()
  • を実装するときは、必ず型パラメーターを指定して、コンパイル時の型の安全性を確保し、またはキャストComparableを使用する必要がないようにしてください。instanceof

    class Tok implements Comparable<Tok> {
        // snip
    
        public int compareTo(Tok other) {
            // snip
        }
    }
    
于 2012-11-22T17:13:11.950 に答える
5

0を返すことは、thisoが等しいことを意味します。これは、oがnullの場合は当てはまりません。また、thisnullになることはありません。

もちろん、アプリケーションに依存します。nullに等しいオブジェクトが必要になる場合があります。そこに返すものはあなた次第ですが、一般的なnullセーフな方法を探しているのであれば、それは本当に理想的ではありません。

完全に一般的であるために、私はそうであるかどうかをチェックonull、もしそうなら、ある種の例外をスローします。

于 2012-11-22T17:12:08.597 に答える
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); 
  } 

さらにそれを完璧なクラスにするために、Tokは最終的なものでなければなりません! (そうしないと、Tok からサブクラス化するときに問題が発生する可能性があります。(Sun は Class Date でそのエラーを作成しました)

final class Tok {
    int rang;
}

比較と等号の処理は必ずしも簡単ではありません。ツリー (TreeMap) の代わりに HashMap を使用することを検討してください。そうすれば、compareTo を実装する必要はありません。this.rang を返すだけの hashCode を実装する必要があります。

最後に、equals() の実装を強くお勧めしますが、必須ではありません。

public boolean equals(Object obj) {
return obj instanceof Tok
    && this.rang() == ((Tok) obj).rang;
}
于 2012-11-22T17:45:21.050 に答える
1

奇妙に見えるかもしれませんが、安全ではありません。TokをTreeSetまたはTreeMapに(キーとして)追加しようとすると、NullPointerExceptionが発生します。問題は、TreeSetの実装がTreeMapに基づいていることです。あなたがadd(null)しようとすると、基礎となるマップはあなたのnullを入れようとし、その結果NPEになります

于 2012-11-22T17:36:49.763 に答える
1

2 つのオブジェクトの比較は、他のメソッドと同じように null セーフにすることができます。ここでの問題は、通常のメソッドには 2 つのパラメーターがありますが、compareTo1 つを受け取り、もう 1 つはオブジェクト自体であるということです。

thisnull にすることはできません。これは、nullオブジェクト (インスタンスなし) でコードを実行していることを意味します。この場合、 aNullPointerExceptionが呼び出された直後にスローされ、compareToそのコードの実行が不可能になります。

オブジェクトと同じ数のアプローチがあります。比較は、null になる可能性があるクラスのフィールドに基づくことができるためです (プリミティブ型を除外するための意図的なキャップ)。したがって、簡単に言えば、null チェックは、パラメーターとして受け取るオブジェクトcompareToと使用されるフィールドをカバーする必要があります。さらに、何らかのロジック (ユーティリティ クラスなど) を保持する外部インスタンスがある場合は、そのインスタンスも null かどうかを確認する必要があります。

補足として、関連するオブジェクトが含まれている場合に返すものはすべて、null一貫性があり、文書化されている必要があります (最初または最後に null を配置するために、-1 または 1 を返すことができます)。0 を返さないようにしてください (これは、オブジェクトに対してequals返さtrueれた場合と同じです。null

于 2012-11-22T17:18:24.537 に答える
1

作成者は、Tok[] から null 値を削除したくないと主張しています。
これは、NULL値でソートできるソウルションであり、Java契約に違反していません

これを回避するには、compareTo コントラクトに違反するクラス Tok 内に 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));
    }
}

単純化されたクラス Tok (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
于 2012-11-23T14:03:54.013 に答える