オブジェクトソート時の順序関係を規定するには？

## 以下のインターフェースのいずれかを実装したクラスを定義する必要がある。

* java.lang.Comparable
    * Javaコアクラスが実装している
    * オブジェクト全体に自然順序づけを強制する。（compareToメソッド）
    * 実装したオブジェクトの配列はCollection.sort()もしくはArrays.sort()によってソートされる。


* java.util.Comparator
    * クライアントが独自の順序でオブジェクトソートしたい時に使う。



## Comparableインターフェース

``` java
public interface Comparable<T> {
	public int compareTo(T o);
}
```

Comparableを実装しているクラス
Integer, Double, File, Enum など...
Comparableインターフェースを実装したクラスは、保存されるオブジェクト自身で比較が行われる。
### Comparableを実装しているInteger

具体的にIntegerクラスで、比較できる仕組みをみてみる。

``` java
public final class Integer extends Number implements Comparable<Integer> {
	public int compareTo(Integer anotherInteger) {
		return compare(this.value, anotherInteger.value);
	}
	// 保持する値の比較
	// 自Obj < 比較対象Obj ならば-1
	// 自Obj = 比較対象Obj ならば0
	// 自Obj > 比較対象Obj ならば1
	public static int compare(int x, int y) {
		return (x < y) ? -1 : ((x == y) ? 0 : 1);		
	}
}
```

使用例

``` java
// 並び替え
List<Integer> integerList = new ArrayList<Integer>();
integerList.add(new Integer(5));
integerList.add(new Integer(2));
integerList.add(new Integer(3));
integerList.sort(null);
for (Integer integer : integerList) {
	System.out.println(integer);
} // 2 3 5
// 比較
System.out.println(new Integer(3).compareTo(new Integer(5))); // -1
System.out.println(new Integer(3).compareTo(new Integer(3))); // 0
System.out.println(new Integer(5).compareTo(new Integer(3))); // 1
List<String> stringList = new ArrayList<String>();
stringList.add("c");
stringList.add("d");
stringList.add("a");
stringList.sort(null);
for(String str : stringList) {
	System.out.println(str);
} // a c d
```

## Comparatorインターフェース

``` java
public interface Comparator<T> {
	int compare(T o1, T o2);
	boolean equals(Object obj);
	default Comparator<T> reversed() {
		return Collections.reverseOrder(this);
	}
	// そのほかにもメソッドを持つ
	......
}
```

### Comparatorによる独自順序づけとComparableによる自然順序づけとTreeSetの使用例

**java.util.TreeMap**

* このクラスでは、格納する要素はComparableを実装したオブジェクトであることを前提とする。

* Comparableを実装していないとエラーがでる。



``` java
class Employee implements Comparable<Employee>{
	private String name;
	private Integer id;
	private Date birth;

	public Employee(String name, Integer id, Date birth) {
		this.name = name;
		this.id = id;
		this.birth = birth;
	}

	public Integer getId() {
		return id;
	}

	public String getName() {
		return name;
	}
	public Date getBirth() {
		return birth;
	}

	public String toString() {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
		Calendar cal = Calendar.getInstance();
		cal.setTime(birth);
		return "name=" + name + " id=" + id + " birth" + dateFormat.format(cal.getTime());
	}

	/**
	 * idを比較します
	 * @param obj1
	 * @param obj2
	 * @return
	 */
	public int compare(Employee obj1, Employee obj2) {
		return obj1.getId().compareTo(obj2.getId());
	}

	@Override
	public int compareTo(Employee o) {
		return compare(this, o);
	}
}
/**
 * EmployeeのIDを元に比較をします
 *
 */
class SortID implements Comparator<Employee> {
	@Override
	public int compare(Employee obj1, Employee obj2) {
		return obj1.getId().compareTo(obj2.getId());
	}
}
/**
 * EmployeeのBirthを元に比較をします
 *
 */
class SortBirth implements Comparator<Employee>{
	@Override
	public int compare(Employee o1, Employee o2) {
		return o1.getBirth().compareTo(o2.getBirth());
	}

}

class SortSample {
	public static void main(String[] args) {
		Calendar cal = Calendar.getInstance();
		cal.set(1990, 01, 05);
		Employee e1 = new Employee("aya", 20, cal.getTime());
		cal.set(1990, 01, 01);
		Employee e2 = new Employee("jon", 10, cal.getTime());
		cal.set(1990, 01, 02);
		Employee e3 = new Employee("ryu", 50, cal.getTime());

		TreeSet<Employee> treeset = new TreeSet<Employee>();
		treeset.add(e1);
		treeset.add(e2);
		treeset.add(e3);
		System.out.println("TreeSetに格納されたEmployeeのcompareTo()に基づきIDの昇順で表示");
		print(treeset);

		TreeSet<Employee> treesetBirth = new TreeSet<Employee>(new SortBirth());
		treesetBirth.add(e1);
		treesetBirth.add(e2);
		treesetBirth.add(e3);
		System.out.println("TreeSetに格納されたEmployeeをSortBirthで定義したbirthの昇順での表示");
		print(treeset);

		ArrayList<Employee> ary = new ArrayList<Employee>();
		ary.add(e1);
		ary.add(e2);
		ary.add(e3);
		System.out.println("ArrayList のインデックス順での表示");
		print(ary);

		Collections.sort(ary, new SortID());
		System.out.println("SortID で定義したid の昇順での表示");
		print(ary);

		Collections.sort(ary, new SortBirth());
		System.out.println("SortBirth で定義したbirthの昇順での表示");
		print(ary);
	}

	public static void print(Collection<Employee> ary) {
		for (Employee obj : ary) {
			System.out.println(obj);
		}
	}
}
```

実行結果

```
TreeSetに格納されたEmployeeのcompareTo()に基づきIDの昇順で表示
name=jon id=10 birth1990/02/01
name=aya id=20 birth1990/02/05
name=ryu id=50 birth1990/02/02
TreeSetに格納されたEmployeeをSortBirthで定義したbirthの昇順での表示
name=jon id=10 birth1990/02/01
name=aya id=20 birth1990/02/05
name=ryu id=50 birth1990/02/02
ArrayList のインデックス順での表示
name=aya id=20 birth1990/02/05
name=jon id=10 birth1990/02/01
name=ryu id=50 birth1990/02/02
SortID で定義したid の昇順での表示
name=jon id=10 birth1990/02/01
name=aya id=20 birth1990/02/05
name=ryu id=50 birth1990/02/02
SortBirth で定義したbirthの昇順での表示
name=jon id=10 birth1990/02/01
name=ryu id=50 birth1990/02/02
name=aya id=20 birth1990/02/05
```

#### TreeSetにStringを入れる

```java
class TreeSetSample{
	  public static void main(String[] args) {
		    HashSet<String> hash = new HashSet<String>();
		    hash.add("D"); hash.add("B"); hash.add("C");
		    System.out.println("HashSet : " + hash);
		    TreeSet<String> tree = new TreeSet<String>();
		    tree.add("D"); tree.add("B"); tree.add("C");
		    System.out.println("TreeSet : " + tree);
		  }
}
```


## StringでのComparableについて
StringクラスはComparableのcompareToを実装しつつ、
大文字小文字を無視するためにComparatorも定義してString.CASE_INSENSITIVE_ORDERフィールドを持っている。

```java
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {

    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

    public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                         = new CaseInsensitiveComparator();
    private static class CaseInsensitiveComparator
            implements Comparator<String>, java.io.Serializable {
        // use serialVersionUID from JDK 1.2.2 for interoperability
        private static final long serialVersionUID = 8575799808933029326L;

        public int compare(String s1, String s2) {
            int n1 = s1.length();
            int n2 = s2.length();
            int min = Math.min(n1, n2);
            for (int i = 0; i < min; i++) {
                char c1 = s1.charAt(i);
                char c2 = s2.charAt(i);
                if (c1 != c2) {
                    c1 = Character.toUpperCase(c1);
                    c2 = Character.toUpperCase(c2);
                    if (c1 != c2) {
                        c1 = Character.toLowerCase(c1);
                        c2 = Character.toLowerCase(c2);
                        if (c1 != c2) {
                            // No overflow because of numeric promotion
                            return c1 - c2;
                        }
                    }
                }
            }
            return n1 - n2;
        }

        /** Replaces the de-serialized object. */
        private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
    }
}
```

```java

class StringSortSample {
	public static void main(String[] args) {
		List<String> list = Arrays.asList("B", "a", "123", "c");
		System.out.println("Collections.sortを使う");
		Collections.sort(list);
		System.out.println(list);
		System.out.println("String.CASE_INSENSITIVE_ORDERを使う");
		Collections.sort(list, String.CASE_INSENSITIVE_ORDER);
		System.out.println(list);
		System.out.println("compareToIgnoreCaseを使う");
		Collections.sort(list, (s1, s2) -> s1.compareToIgnoreCase(s2));
		System.out.println(list);
	}
}
```

実行結果

```
Collections.sortを使う
[123, B, a, c]
String.CASE_INSENSITIVE_ORDERを使う
[123, a, B, c]
compareToIgnoreCaseを使う
[123, a, B, c]
```