web-dev-qa-db-ja.com

パラメータ文字列がnullの場合、int compareTo()は何を返す必要がありますか?

入力パラメータがnullの場合、compareTo()はNullPointerExceptionをスローする必要があると言われています。ただし、フィールドを文字列の型と比較する必要があるクラスを実装しています。これらのフィールドは必須である必要はありません。この場合、私は疑問に思います、

1)入力がnullの場合、何を返す必要がありますか? null以外の文字列は、辞書式にnullよりも大きいか小さい必要がありますか?

そして

2)これが悪い習慣と見なされる場合、裏付けとなる議論はありますか?代わりに空の文字列を使用するようにユーザーに強制する必要がありますか?空の文字列を使用する場合、フィールドが適用されない場合とフィールドが空の場合を混同しませんか?また、例外をスローする必要がある場合は、マニュアルでユーザーに警告する場合を除いて、他に何ができますか?

編集:ここでは自分自身を明確に表現できないかもしれませんが、実装しているプログラムでは、nullになる可能性のある文字列はすべてフィールドまたはクラスであり、nullであってはなりません。言い換えると、compareTo()が使用するオブジェクトをnullにすることはできず、プライベートフィールドのみをnullにすることができます。したがって、この場合、compareTo()を適切に実装すれば、nullフィールドを持つクラスは常に同じと見なされるため、推移的な要件に違反しないと思います。私は正しいですか、それとも私はこれを間違って解釈していますか?

答えてくれてありがとう!

18
zw324

はい、インスタンスフィールドにnullを許可しても問題はありません。ソート順が定義されていることを確認してください。最も自然なのは、すべての実際の文字列の前または後に置くことですが、ここでは何でもできます。一貫して行うだけです。 (たとえば、nullを_"null"_のように並べ替えることができます。)

単一メンバーの実装例を次に示します。

_class Example implements Comparable<Example> {

   @Nullable
   private String member;

   // TODO: getter, setter, constructor, ...

   public int compareTo(Example that) {
      if(this.member == null)
         if(that.member == null)
            return 0; //equal
         else
            return -1; // null is before other strings
       else // this.member != null
         if(that.member == null)
            return 1;  // all other strings are after null
         else
            return this.member.compareTo(that.member);
   }
}
_

Comparable.compareTo()の指定には、o.compareTo(null)- null.compareTo(o)と同じように動作する、つまりNullPointerExceptionをスローする)の制約のみがあり、nullフィールドが処理されます(フィールドについてはまったく言及されていないため、反対称、再帰性、推移性が保証されている限り、クラスは必要なものを返すことができます)。

14
Paŭlo Ebermann

Javadocから Comparable

Nullはどのクラスのインスタンスでもないことに注意してください。また、e.equals(null)がfalseを返しても、e.compareTo(null)はNullPointerExceptionをスローする必要があります。

25
Bala R

例外に違反しているため、例外をスローしないことは悪い習慣です。 推移的 compareToの反対称の性質。

から Comparable.compareTo ドキュメント:

実装者は、すべてのxとyに対してsgn(x.compareTo(y))== -sgn(y.compareTo(x))を確認する必要があります。 (これは、y.compareTo(x)が例外をスローする場合、x.compareTo(y)が例外をスローする必要があることを意味します。)

実装者は、関係が推移的であることも確認する必要があります。(x.compareTo(y)> 0 && y.compareTo(z)> 0)は、x.compareTo(z)> 0を意味します。

最後に、実装者は、すべてのzについて、x.compareTo(y)== 0がsgn(x.compareTo(z))== sgn(y.compareTo(z))を意味することを確認する必要があります。

さらに重要なことに、同じ理由で、オブジェクトでcompareToを使用して文字列と比較することはお勧めできません:sign(obj.compareTo(str)) != -sign(str.compareTo(obj))。カスタムを実装する Comparator そしてあなたがやりたいことは何でもします。

7
ykaganovich

compareToのドキュメントにはNullPointerExceptionをスローする必要があると記載されているため、実装がインターフェイスのドキュメントと一致するように、これらのガイドラインに従う必要があります。これは、null以外の文字列が辞書式にnullよりも小さいか大きいかという問題も処理します。

これを処理する方法については、いくつかのオプションがあります。空と該当なしが異なる場合は、文字列フィールドを独自のフィールドクラスでラップする必要があります。たとえば、isApplicableメソッドを持つ可能性のあるタイプのMyFieldを作成できます。これは、フィールドがこのケース(または同様のもの)に適用できるかどうかを示します。または、デザインを再考して、空の文字列とN/Aが実際には2つの異なるものであることを確認することもできます。もしそうなら、あなたは2つを区別する方法が必要です。

3
Jeff Storey

Nullがnull以外の値よりも大きいか小さいかを判断する必要があります。クラスの自然順序付けのニーズを満たすようにcompareToを設計できるため、悪い習慣ではありません。

3
Steve Kuo