The HIRO Says

If you smell what The HIRO is cooking!!!

compareTo() メソッド(1)−基本的な実装方法

equals()・hashCode() と同様にオブジェクトの比較に使用できる、compareTo() メソッドについて記述します。


compareTo() メソッドとは?(概要)

オブジェクト同士を比較し、どちらが大きいか小さいかを比較することが目的です。
equals() メソッドは、オブジェクト同士が等しいか等しくないかは確認できますが、どちらが大きいか小さいかまではわかりません。
そこで、compareTo() メソッドが必要になってきます。


compareTo() メソッドの仕様

まず、java.lang.Comparable インターフェースを実装することが大前提です。
その上で、以下の仕様に従う必要があります。

  1. this > argument ならば、正の値(通常+1)を返す。
  2. this = argument ならば、ゼロを返す。
  3. this < argument ならば、負の値(通常−1)を返す。

compareTo() メソッドの規約

上記仕様に加えて、compareTo() メソッドの実装は、以下の規約に従わなければなりません。

  1. a.compareTo(b) = - (b.compareTo(a)) であること。(symmetry)
  2. a.compareTo(b) > 0 かつ b.compareTo(c) > 0 ならば、a.compareTo(c) > 0 となること。(transitivity)
  3. a.compareTo(b) = 0 ならば、a.compareTo(c) = b.compareTo(c) となること。(reflexivity)
  4. a.compareTo(b) = 0 ならば、a.equals(b) = true となること。(必須ではないが推奨)
  5. 引数が異なるクラスの場合、ClassCastException をスローすること。
  6. 引数が null の場合、NullPointerException をスローすること。

compareTo() メソッドの役割

コレクション・フレームワークの(java.util.Collection、List/Set/Map)の一部で、格納されている値同士の比較に使用されています。
【具体的なクラス】

  1. TreeSet
  2. TreeMap
  3. Collections
  4. Arrays

なお、HashMap などでは、compareTo() メソッドではなく hashCode() メソッドを使用しています。


実装例

equals() メソッドの説明で使用した ComplicateObject を元に、compareTo() メソッドの実装例を記します。

import java.util.Date;

// ●implements の仕方に注目
public class ComplicateObject implements Comparable {

// fields
    private boolean booleanValue;
    private byte    byteValue;
    private char    charValue;
    private short   shortValue;
    private int     intValue;
    private long    longValue;
    private float   floatValue;
    private double  doubleValue;
    private String  stringValue;
    private Date    dateValue;


    public int compareTo(ComplicateObject target) {
        // ●float/double に注意(== ではなく compare() メソッドで判断すること)

        if (target == null) {
            // 引数が null の場合、比較する必要なし。
            throw new NullPointerException();
        }

        // ●booleanValue
        if (this.booleanValue == true && target.booleanValue == false) {
            return 1;
        }
        if (this.booleanValue == false && target.booleanValue == true) {
            return -1;
        }

        // ●byteValue
        if (this.byteValue > target.byteValue) {
            return 1;
        }
        if (this.byteValue < target.byteValue) {
            return -1;
        }

        // ●charValue
        if (this.charValue > target.charValue) {
            return 1;
        }
        if (this.charValue < target.charValue) {
            return -1;
        }

        // ●shortValue
        if (this.shortValue > target.shortValue) {
            return 1;
        }
        if (this.shortValue < target.shortValue) {
            return -1;
        }

        // ●intValue
        if (this.intValue > target.intValue) {
            return 1;
        }
        if (this.intValue < target.intValue) {
            return -1;
        }

        // ●longValue
        if (this.longValue > target.longValue) {
            return 1;
        }
        if (this.longValue < target.longValue) {
            return -1;
        }

        // ●floatValue
        int floatDiff = Float.compare(this.floatValue, target.floatValue);
        if (floatDiff > 0) {
            return 1;
        }
        if (floatDiff < 0) {
            return -1;
        }

        // ●doubleValue
        int doubleDiff = Double.compare(this.doubleValue, target.doubleValue);
        if (doubleDiff > 0) {
            return 1;
        }
        if (doubleDiff < 0) {
            return -1;
        }

        // ●stringValue
        if (this.stringValue != null && target.stringValue == null) {
            return 1;
        }
        if (this.stringValue == null && target.stringValue != null) {
            return -1;
        }

        if (this.stringValue != null && target.stringValue != null) {
            int stringDiff = this.stringValue.compareTo(target.stringValue);
            if (stringDiff > 0) {
                return 1;
            }
            if (stringDiff < 0) {
                return -1;
            }
        }

        // ●dateValue
        if (this.dateValue != null && target.dateValue == null) {
            return 1;
        }
        if (this.dateValue == null && target.dateValue != null) {
            return -1;
        }

        if (this.dateValue != null && target.dateValue != null) {
            int dateDiff = this.dateValue.compareTo(target.dateValue);
            if (dateDiff > 0) {
                return 1;
            }
            if (dateDiff < 0) {
                return -1;
            }
        }

        // いずれの値も等しかった場合
        return 0;
    }


// getter/setter/constructor は省略
}