Effective Javaを読むチャレンジ-項目12-

項目12 Comparableの実装を検討する

java.lang.Comparableインターフェースを実装したクラスは、自然順序を持っていることを表します。つまり、Arrays.sortメソッドで簡単にソートができる、というメリットがあります。

なので、自然な順序を持っていそうな値クラスを作るときは、Comparableの実装を検討した方がよい、ということです。

Comparableインターフェースの唯一のメソッドであるcompareToメソッドは、オブジェクトと引数を比較して、その結果が正なら1、等しいなら0、負なら-1の3パターンの整数を返す必要がありますが、いつもオブジェクトが大きい場合が1なんだか-1なんだか忘れてしまうんですよね。compareToメソッドの戻り値のパターンを簡単にまとめると以下のようになります。

  • x.compareTo(y)のとき、x > y なら、1を返す。
  • x.compareTo(y)のとき、x == y なら、0を返す。
  • x.compareTo(y)のとき、x < y なら、-1を返す。

compareToメソッドの一般契約を簡単にしてみます。

  • compareToメソッドは上記の戻り値のパターンとなる
  • x.compareTo(y)とy.compareTo(x)の結果は逆になる
  • x.compareTo(y)とy.compareTo(z)の結果がともに正なら、x.compareTo(z)も正(推移性)
  • x.compareTo(y)が0なら、x.compareTo(z)とy.compareTo(z)の結果は同じ
  • x.compareTo(y)が0なら、x.equals(y)がtrueを返す(必須ではないが強く推奨)
  • xとyのクラスが異なるとき、ClassCastExceptionを返す
  • 引数がnullの場合、NullPointerExceptionを返す

注意する点は、値クラスがComparableを実装する時、equalsと同じことが起きるというところですね。つまり、値クラスのサブクラスでフィールドを追加した場合、compareToメソッドは一般契約と矛盾する、ということです。対策もだいたいequalsと同じで、コンポジションを使うことです。

また、値クラスのフィールドを比較するとき、基本データ型は不等号を使った比較を行いますが、浮動小数点に関しては、Float.compareメソッドやDouble.compareメソッドを使わなければなりません。

そして、フィールドが複数ある場合は、その比較する順序も重要ということです。たとえば電話番号をフィールドにもつ値クラスだった場合、電話番号の市外局番だけを先に比較すれば、残りの番号の比較をする必要がなくなるかもしれないからです。

という感じで、特に難しい説明もなく読み終わってしまいました。項目数でいえばまだ全体の6分の1程度、まだまだ先は長いです。

広告
  • LINEで送る