クラスライブラリ基礎

Collections クラスの利用

Collections Framework に属するデータ構造に対する操作が、 Collections クラスのメソッドとして提供されています。 この使い方を学びます。

Collections クラスのメソッド

Collections クラスには、 リスト、セットといった構造を操作するための便利なメソッドが実装されています。

これらのメソッドはクラスメソッド(static メソッド)として実装されているので、 Collections クラスのインスタンスを作ることなく利用することができます。

    // リストを生成
    ArrayList<T> list = new ArrayList<T>();

    // ここでリストにデータを追加
    ...
    
    // リストをソート
    Collections.sort(list);

ソート(並び替え)

データを一定の順序に並び替えることをソーティング(sorting)と言います。 ソートのアルゴリズムにはさまざまなものがありますが、 Java の Collections クラスにはマージソートと呼ばれるアルゴリズムの改良版が実装されていて、 自分で並び替えのプログラムを作らなくても、並び替えができます。

ただし、データを並び替えてもらうには前準備が必要です。 データをどのような順序で並べるのかを指示する必要があります。 その方法として、以下の2種類があります。

Comparable インタフェース

ソートをするためには、どうやって順序を決めるか、はっきりさせなければなりません。 任意の2つのオブジェクトを比較したときに、どちらが前でどちらが後ろかが、 はっきり定義されていることが必要です。

1つの方法として、 データであるオブジェクトを表すクラスに Comparable インタフェースを実装する方法があります。 これは自分自身と他のオブジェクトを比較する compareTo(Object object) というメソッドを実装することにより、 オブジェクトの間の順番を決定する、というものです。

例えば、String クラスは Comparable<String> インタフェースを実装しているので、 メソッド compareTo(String anotherString) があります。

比較した結果は int の数値として返されます。自分が相手よりも前なら負、後ろなら正、等しければ 0 となります。

この String オブジェクトによって表される文字シーケンスが、引数文字列によって表される文字シーケンスと辞書的に比較されます。この String オブジェクトが辞書的に引数文字列より前にある場合は、結果は負の整数になります。この String オブジェクトが辞書的に引数文字列の後ろにある場合、結果は正の整数になります。文字列が等しい場合、結果は 0 になります。

リストの要素がString クラスのオブジェクトの場合には、 String クラスが Comparable インタフェースを実装しているため、 そのまま Collections.sort(Collection) が使えます。 一方、自分で定義したクラス、 例えば Music クラスのオブジェクトがリストの要素になっている場合、 自分で compareTo メソッドを実装する必要があります。

import java.util.*;

class SortedMusicListenerWithComparable {
    public static void main(String[] args) {
	ArrayList<Music> musicList = new ArrayList<Music>();

	musicList.add(new Music("Tour de France (Radio Version)", "Kraftwerk"));
	musicList.add(new Music("Tour de France (Kling Klang Analog Mix)", "Kraftwerk"));
	musicList.add(new Music("Tour de France (Remix Francois K.)", "Kraftwerk"));
	musicList.add(new Music("Hallo Gallo", "Neu!"));

	Collections.sort(musicList);

	for(Music music: musicList)
	    System.out.println(music.getTitle() + " by " + music.getArtist());
    }
}

class Music implements Comparable<Music> {
    private String title;
    private String artist;
    public Music(String title, String artist) {
	this.title = title;
	this.artist = artist;
    }
    public String getTitle() {
	return title;
    }
    public String getArtist() {
	return artist;
    }
    // タイトルで比較
    public int compareTo(Music another) {
	String anotherTitle = another.getTitle();
	int result;
	if(title.compareTo(anotherTitle) < 0)
	    // 自分が相手よりも前
	    result= -1;
	else if(title.compareTo(anotherTitle) > 0)
	    // 自分が相手よりも後
	    result = 1;
	else
	    // それ以外=同一順位
	    result = 0;
	return result;
	// 以下でも同様
	// return title.compareTo(another.getTitle());
    }
}

Comparator インタフェース

順序を付ける方法を指示するもう一つの方法として、 順序づけを担当する専用のクラスを作成する、という方法があります。 この方法は、順序づけの方法が後から変わる可能性がある場合や、 データを表すクラスが変更できない場合に有効でしょう。

2つのオブジェクトを引数にとる compare メソッドを実装することになります。 戻り値は compareTo と同様に int の値です。

import java.util.*;

class SortedMusicListenerWithComparator {
    public static void main(String[] args) {
	ArrayList<Music> musicList = new ArrayList<Music>();

	musicList.add(new Music("Tour de France (Radio Version)", "Kraftwerk"));
	musicList.add(new Music("Tour de France (Kling Klang Analog Mix)", "Kraftwerk"));
	musicList.add(new Music("Tour de France (Remix Francois K.)", "Kraftwerk"));
	musicList.add(new Music("Hallo Gallo", "Neu!"));

	Collections.sort(musicList, new MusicComparator());

	for(Music music: musicList)
	    System.out.println(music.getTitle() + " by " + music.getArtist());
    }
}

class Music {
    private String title;
    private String artist;
    public Music(String title, String artist) {
	this.title = title;
	this.artist = artist;
    }
    public String getTitle() {
	return title;
    }
    public String getArtist() {
	return artist;
    }
}

class MusicComparator implements Comparator<Music> {
    // 順序付けのために 2 つの引数を比較します。
    public int compare(Music music1, Music music2) {
	return music1.getTitle().compareTo(music2.getTitle());
    }          
}