未来エンジニア養成所Blog

プログラミングを皆に楽しんでもらうための情報をお届けします。

【Java】コレクション Part5

title

前回に引き続きコレクションの解説です。

前回までの記事はこちら phoeducation.work phoeducation.work phoeducation.work phoeducation.work


オブジェクトの順序付け

コレクションを扱う場合、格納されたデータが何らかの順序付けによって並べ替えられていると、項目を取り出して検索するときなどに便利です。

ここでは、コレクションに格納されたオブジェクトがどのように順序付けされているのかを見ていきます。

コレクションに格納されているデータはコレクションの種類によって、順序付けされているものとされていないものがあります。

ここでいう順序付けとは、自然順序付けといい、文字列は辞書順、数値は昇順に並べ替えられるものです。

TreeSetやTreeMapに格納されるデータは自然順序付けで並び替えられて格納されています。


【自然順序付け】

import java.util.HashSet;
import java.util.TreeMap;
import java.util.TreeSet;
public class CollectionSample10{
    public static void main(String args [ ]){
        HashSet<String> hashset = new HashSet<String>( );
        hashset.add("Z");
        hashset.add("A");
        hashset.add("X");
        System.out.println("HashSet内のデータ:" + hashset);

        TreeSet<String> treeset = new TreeSet<String>( );
        treeset.add("Z");
        treeset.add("A");
        treeset.add("X");
        System.out.println("TreeSet内のデータ:" + treeset);

        TreeMap<Integer,String> treemap = new TreeMap<Integer,String>( );
        treemap.put(new Integer(3),"X");
        treemap.put(new Integer(1),"Z");
        treemap.put(new Integer(2),"A");
        System.out.println("TreeMap内のデータ:" + treemap);
    }
}


実行結果

HashSet内のデータ:[A, X, Z]
TreeSet内のデータ:[A, X, Z]
TreeMap内のデータ:{1=Z, 2=A, 3=X}


HashSetオブジェクトに「Z、A、X」の値を格納して、標準出力すると、「AXZ」と並べ替えられたように見えます。

しかしHashSetは並び替えの保証がないので、毎回このような結果になるとは限りません。

次にTreeSetオブジェクトに「Z、A、X」の値を格納して、標準出力すると、並べ替えが辞書順でおこなわれ、「AXZ」と表示されているのが分かります。

またTreeMapオブジェクトにキーとしてIntegerオブジェクト「3,1,2」を格納し、そのそれぞれに対応した値を「XZA」と格納し、標準出力すると、キーの部分の並べ替えがおこなわれ、「123」の順で表示されているのが分かります。


ここまで見てきた、自然順序付けは、ComparableというインターフェースのcompareTo( )のオブジェクト比較のルールにのっとっています。


ComparableインターフェースのcompareTo( )による自然順序付け
ComparableインターフェースのcompareTo( )メソッドはオブジェクトの並び順を決定します。

このメソッドには、下の表のような比較ルールがあります。

自分のオブジェクトと、あるオブジェクトを比較したとき、両者が同じ場合は戻り値としてint型のデータ0を返します。

自分のオブジェクトが比較対象のオブジェクトより小さい場合は、小さいほうを前に並び替えて、戻り値は負の数を返します。

また自分のオブジェクトより比較対象のオブジェクトが大きい場合は、大きいほうを後ろに並び替えて、戻り値の正の数を返します。


public int compareTo( )は、自分のオブジェクト.compareTo(比較したいオブジェクト) と記述します。


【オブジェクトの比較ルール】
オブジェクトの比較ルール


StringやIntegerクラスはComparableインターフェースを実装しているため、ComparableインターフェースのcompareTo( )のオブジェクト比較ルールにのっとって比較されます。

また、TreeSetやTreeMapに格納するオブジェクトはComparableインターフェースを実装したオブジェクトでなければなりません。


【ComparableインターフェースのcompareTo()】

public class CollectionSample11 {
    public static void main(String[] args) {
        System.out.println( "A".compareTo( "A" ) );
        System.out.println( "A".compareTo( "C" ) );
        System.out.println( "C".compareTo( "A" ) );
    }
}


実行結果

0
-1
2


StringクラスのオブジェクトをcompareTo()で比較した例です。

  • 「A」と「A」の比較では両者が等しいので0を返します
  • 「A」と「C」の比較は「A」が「C」より並び順で、2つ分小さいので-2を返します
  • 「C」と「A」の比較では、「C]が「A」より並び順で、2つ分大きいので2を返します

ここではStringクラスオブジェクトの比較例を見ていきましたが、実はStringクラスやIntegerクラスはComparableインターフェースを実装しているため、compareTo()を使用することができ、そのルールに従って結果を出すことができるのです。

またTreeSetやTreeMapに格納するオブジェクトはComparableインターフェースを実装したオブジェクトでないといけません。


Comparableインターフェースを実装していないオブジェクトをTreeSetなどに格納すると、実行時エラーになります。

StringやIntegerクラスなどは、Comparableインターフェースを実装したクラスとして提供されているためTreeSetに格納し、使用することができるのです。


コレクションに格納されるオブジェクトの並べ替え順を独自に定義する
これまで、オブジェクトの比較は、Comparableインターフェースに定義されているcompareTo( )のオブジェクトの比較ルールに従って並び替えられることをみてきました。

では、オブジェクトを並べ替えるとき、独自のルールを決めたい場合はどうすればよいのでしょう。

ここでは並べ替え順を独自に定義する方法についてみていきましょう。


独自に並べ替えルールを決めるには、2つの方法があります。

  • Comparableインターフェースを実装したクラスで、compareTo( )をオーバーライドする
    public int compareTo(Object o) ・・・自分のオブジェクトと引数に指定したオブジェクトを比較する
  • Comparatorインターフェースを実装したクラスで、compare( )をオーバーライドする
    public int compare(Object o1, Object o2) ・・・引数に指定した2つのオブジェクトを比較する


【Comparableインターフェースを実装したクラスで、compareTo( )をオーバーライドする】

import java.util.TreeSet;
class Name implements Comparable<Name>{
    private String firstname;
    private String lastname;

    public Name(String firstname, String lastname){
        this.firstname = firstname;
        this.lastname = lastname;
    }
    public int compareTo(Name n){
        int last = lastname.compareTo(n.lastname);
        if(last != 0){
            return last;
        }else{
            return firstname.compareTo(n.firstname);
        }
    }
    public String toString( ){
        return lastname + " " + firstname;
    }
}
public class CollectionSample12{
    public static void main(String args [ ]){
        Name name1 = new Name("taro","yamada");
        Name name2 = new Name("hanako","tanaka");
        Name name3 = new Name("jiro","suzuki");
        Name name4 = new Name("ichiro","suzuki");

        TreeSet<Name> ts = new TreeSet<Name>( );
        ts.add(name1);
        ts.add(name2);
        ts.add(name3);
        ts.add(name4);

        for(Name str:ts){
            System.out.println(str.toString( ));
        }
    }
}


実行結果

suzuki ichiro
suzuki jiro
tanaka hanako
yamada taro


では、1つ目のComparableインターフェースを実装したクラスで、compareTo( )をオーバーライドする方法についてみていきましょう。

Nameクラスにはfirstnameとlastnameのフィールドを用意しておきます。


compareTo()をオーバーライドして、Nameオブジェクトのlastnameの昇順に並び替えられるようにします。

そのときの戻り値が0の場合は、比較したオブジェクト同士が同じことを意味するので、その場合は、さらにfirstnameの昇順で並び替えるようにします。


クラスCollectionSample12のmain()でNameオブジェクトをそれぞれ生成し、TreeSetオブジェクトtsに格納しますが、その際に、NameクラスでオーバーライドしたcompareTo()のオブジェクト比較ルールによって並び替えられて格納されます。

そしてさらにNameクラスのtoString()をオーバーライドし、firstnameにつづいてスペースを1ついれlastnameの形で文字列に変換されるようにしておきます。

TreeSetに格納されたtsオブジェクトを、拡張for文を使用して、オーバーライドされたtoString()で文字列に変換しながら標準出力をします。


ComparableインターフェースのcompareTo()をオーバーライドしてオブジェクトの並び替えルールを作る場合は、並び替えたいオブジェクト自身に実装しなければなりません。

この例でいうと、Nameクラスにimplements Comparableと指定をしています。


【Comparatorインターフェースを実装したクラスで、compare( )をオーバーライドする】

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class CollectionSample13 {
    public static void main(String args [ ]){
        List<Employee> list = new ArrayList<Employee>( );
        list.add(new Employee("One"));
        list.add(new Employee("Two"));
        list.add(new Employee("Three"));

        Collections.sort(list,new SortSample1( ));
        System.out.println("---昇順で並び替え---" );
        for(Object temp: list){
            System.out.print((Employee)temp + " ");
        }
        System.out.println( );
        System.out.println("---降順で並び替え---" );
        Collections.sort(list,new SortSample2( ));
        for(Object temp: list){
            System.out.print((Employee)temp + " ");
        }
    }
}

class Employee{
    private String  id;
    public Employee(String id){
        this.id = id;
    }
    public String getId( ){
        return id;
    }
    public String toString( ){
        return this.id + "";
    }
}
class SortSample1 implements Comparator<Employee>{
    public int compare(Employee emp1, Employee emp2){
        return emp1.getId( ).compareTo(emp2.getId( ));
    }
}

class SortSample2 implements Comparator<Employee>{
    public int compare(Employee emp1, Employee emp2){
        return emp2.getId( ).compareTo(emp1.getId( ));
    }
}


実行結果

---昇順で並び替え---
One Three Two
---降順で並び替え---
Two Three One


独自のオブジェクトの並び替えルールを作る方法の2つ目としてComparatorインターフェースを実装し、compare()をオーバーライドする方法を見ていきましょう。

ComparableインターフェースのcompareTo()をオーバーライドしてオブジェクトの並び替えルールを作る場合は、並び替えたいオブジェクト自身に実装しなければなりません。

Comparatorインターフェースでは、並べ替えの方法のみを定義したクラスを作成することができます。

たとえば従業員クラスにおいて、社員番号順、年齢順、名前順など色々な方法で並べ替えを行いたい場合は、複数のComparatorインターフェースを実装したクラスを作成すると、同じオブジェクトに対して、色々な並び替えを行うことができます。


EmployeeクラスにはString型のidフィールドが用意されており、コンストラクタで与えられた引数で初期化されるようになっています。

またゲッターメソッドとtoString()がidとスペースの文字列の変換されるように、オーバーライドされています。

Employeeクラスのidの昇順に並び替えるルールをSortSample1クラスでcompare()をオーバーライドして作成しています。

compare( )内では、compareTo( )を使用して、1つ目のidと2つ目のidを比較し、1つ目のidが小さいとき、1つ目のidを前に持ってきて、昇順に並び替えをします。

同様にEmployeeクラスのidの降順に並び替えるルールをSortSample2クラスでcompare()をオーバーライドして作成しています。


compare( )内では、compareTo( )を使用して、1つ目のidと2つ目のidの順序を先ほどの昇順の場合と逆にして、降順で並び替えるようにしますCollectionSample13クラスのmain()内で、ArrayListを作成し、Employeeオブジェクトを格納します。

Collectionsクラスのsort()はコレクションの要素を並び替えるメソッドです。

第1引数に並び替えをしたいオブジェクトを指定し、第2引数にコンパレータによって作られた並べ替え順のルールのオブジェクト(ここではSortSample1とSortSample2のクラスオブジェクト)を指定すると、そのルールに従って並べかえを行うことができます。

最後に拡張for文を使用して、それぞれの要素をEmployeeクラスのtoString( )によって文字列に変換して、標準出力します。

このようにComparatorインターフェースを実装したクラスにcompare( )をオーバーライドすれば、オブジェクトの並び順のルールを複数作成することができます。


まとめ

  • コレクションフレームワーク
    • コレクションフレームワークとは、複数のオブジェクトをまとめて取り扱うための統一した考え方です。
    • コレクションとは、コレクションフレームワークに基づいて提供されたクラスやインターフェースです。
    • エレメントとは、コレクションに格納する1つ1つのオブジェクト(要素)です。
    • エレメントの格納方法や検索方法の違いなどによって、List、Set、Map、Queueの4つに分類されます。
  • コレクションインターフェースと実装クラス
    • インターフェースはそれ自体をインスタンス化することはできず、実装したクラスをインスタンス化して使用します。
    • 4つのインターフェースにはそれぞれ具象クラスがあります。
  • Setインターフェース
    • SortedSetインターフェースとそれを実装したTreeSet、Setインターフェースを実装したHashSetやLinkedHashSetなどがあります。
    • 順不同でオブジェクトを管理しています。
  • Listインターフェース
    • リストはサイズ変更可能な配列のようなものです。
    • 重複が許されます。
    • オブジェクトを順番で管理し、記憶した順番に、1つ1つのオブジェクトは番号(添字)で管理されています。
  • Mapインターフェース
    • キーと値をペアで管理しており、キーは自動的に並べ替えられます。
  • Queueインターフェース
    • FIFO(First In First Out)と呼ばれる形式のもので、先入れ先出しを表す待ち行列です。
  • Stackクラス
    • LIFO(Last In First Out)と呼ばれる後入れ先出しの配列です。
    • 重複は認められ、順番に管理されています。
  • コレクション要素の取り出し
    • Iteratorとはコレクションに格納された要素を指し示す、カーソルのようなもので、反復子と呼ばれています。
  • Cllectionsクラス
    • コレクションに対して、並べ替えや検索をするためのstaticなメソッドが用意されています。
  • Arraysクラス
    • 配列を並べ替えたり、検索するためのstaticメソッドが用意されています。
  • オブジェクトの順序付け
    • 自然順序付けでは、文字列は辞書順、数値は昇順に並べ替えられます。
    • 自然順序付けは、ComparableインターフェースのcompareTo( )のオブジェクト比較のルールにのっとっています。
    • ComparableインターフェースのcompareTo( )メソッドはオブジェクトの並び順を決定します。
    • コレクションに格納されるオブジェクトの並べ替え順を独自に定義することができます。
    • 並べ替え順を独自に定義するには、Comparableインターフェースを実装したクラスで、compareTo( )をオーバーライドする方法とComparatorインターフェースを実装したクラスで、compare( )をオーバーライドする2つの方法があります。


参考図書



独学で挫折しそうになったら、オンラインプログラミングスクール
未来エンジニア養成所Logo



あわせて学習したい

phoeducation.work phoeducation.work