Javaプログラミング入門 18章 [コレクション]

Java

こんにちは。ECF Techブログ
担当 Michiharu.Tです。

Javaプログラミング入門記事の第18章をお送りいたします。
第18章のテーマは「コレクション」です。
本章を持ちまして、オブジェクト指向編は完結となります。

本連載の初回および章立ての一覧については下記のリンクから確認できます。

Javaプログラミング入門 0章
0章 Javaプログラミングを始めよう こんにちは。ECF Techブログ 担当 Michiharu.Tです。 この記事はプログラミング言語のJavaを、実際に動かしながら学びたい人のための学習教材となっています。手を多く動かすこと、感覚を...

本章ではコレクションについて学びます。

Java標準クラスのうち、インスタンスの集合を表すクラス群をコレクション(クラス)と呼びます。コレクションクラスは、どのインタフェースを実装しているかによって下の表に示す3つに大別されます。

名称 インスタンスの持ち方の特徴
リスト 配列のようなデータ構造で、要素数を必要に応じて変動できる。
セット シンプルなインスタンスの集合を表現する。重複したデータを持てない。
マップ キーと値のペアで情報を管理する。キーは重複できない。

本章では上記3つのコレクションについて、プログラム例を示しながらご紹介します。

18-1 リスト

まず始めにリストについて見ていきましょう。リストは配列のようなデータ構造です。

リストは下の図に示すように、配列とほぼ同じ感覚で使うことができます。ですが、配列と異なる大きなメリットとして、あらかじめ要素数を指定しておく必要がありません。リストの要素は値の追加と共に自動的に増加します。

リストイメージ

では実際にプログラム例を見ていきましょう。リストの代表的なクラスであるArrayListを使ったプログラムです。

プログラム例(Main.java)

import java.util.ArrayList;
public class Main {
    public static void main(String[] args) {
        //インスタンスの生成・・・(1)
        ArrayList<String> list = new ArrayList<>();
        //要素の追加・・・(2)
        list.add("リンゴ");
        list.add("みかん");
        list.add("バナナ");
        //要素の取得・・・(3)
        System.out.println(list.get(1));
        //要素数の取得・・・(4)
        System.out.println(list.size());
    }    
}

実行結果

みかん
3

解説
コメント(1)のプログラムのように、コレクションクラスの変数宣言およびインスタンス生成の文法は、これまでの記述とは少し異なります。インスタンス生成時の基本的な文法を示します。

コレクションクラス名<型名> 変数名 = new コレクションクラス名<>();

型名の部分にはコレクションクラスが保持するインスタンスの型を記述します。今回のプログラムでは文字列を保持したいのでStringとなっています。なお、<型名>の部分の書き方をジェネリクス表記と言います。

リストの操作
リストの操作はメソッドを使って行います。リストの持つ主なメソッドを示します。

定義部 動作概要
boolean add(E e) 指定された要素をリストの最後に追加する。
E get(int index) リスト内の指定された位置にある要素を返す。
boolean clear() すべての要素をリストから削除する。
boolean contains(Object o) 指定された要素がリストに含まれている場合にtrueを返す。
int size() リスト内の要素の数を返す。

※表中のEの表記は、ジェネリクス表記で指定した型に置き換えて読んでください。

要素の追加にはaddメソッドを使います。コメント(2)の部分では3つの文字列をリストに追加しています。この時点でリストは下図のような状態になっています。

リストの状態

コメント(3)の部分ではリストから要素を取り出し、画面に表示しています。要素を取り出す時はgetメソッドを使います。引数は添字にあたります。配列と同様0から始まります。例ではlist.get(1)となっていますので、0から数えて1番目にある「みかん」が戻り値として返されます。

最後のコメント(4)の部分では、要素数の取得を行っています。要素数の取得はsizeメソッドで行います。この時点における要素数は3ですので、戻り値として3が返され、画面に表示されています。

18-1-1 拡張for文

リストの各要素に対して処理を行いたい場合は、拡張for文が便利です。拡張for文の文法は次のようになります。

for(型 変数名:リストや配列){
    //各要素に対する処理
}
  • 型には、リストや配列に格納されている要素の型と同じものを指定します。
  • くり返しのたびに、リスト内の要素が次々と変数に代入されます。

プログラム例を示します。

プログラム例(Main.java)

import java.util.ArrayList;
public class Main {
    public static void main(String[] args) {
        //インスタンスの生成
        ArrayList<String> list = new ArrayList<>();
        //要素の追加
        list.add("リンゴ");
        list.add("みかん");
        list.add("バナナ");
        //拡張for文による表示・・(1)
        for( String data : list ){
            System.out.println(data);
        }
    }    
}

実行結果

りんご
みかん
バナナ

コメント(1)の部分で拡張for文を使用しています。for文の宣言部for( String data : list )は、「list内の要素を1つ1つ変数dataに入れながらくり返す」と解釈すると良いでしょう。下図のように、変数dataの指す値は、くり返しのたびに異なります。

拡張for文

18-2 セット

本節ではセットについてご紹介します。セットはシンプルなインスタンスの集まりです。箱の中に雑多にインスタンスが入っている。というイメージを持つと良いでしょう(下図)。

セットのイメージ

そのため、次のような特徴を持ちます。

  • 順序の概念がない
  • 重複したデータは入れられない

それでは、実際のプログラムを例に確認しましょう。セットの代表的なクラスであるHashSetを使用します。

プログラム例(Main.java)

import java.util.HashSet;
public class Main {
    public static void main(String[] args) {
        //インスタンス生成・・・(1)
        HashSet<String> set = new HashSet<>();
        //要素を追加・・・(2)
        set.add("リンゴ");
        set.add("みかん");
        set.add("バナナ");
        set.add("バナナ");
        //現在のセットの状況を表示・・・(3)
        System.out.println(set);
        //拡張for文により値を取得・・・(4)
        for( String str : set ){
            System.out.println(str);
        }
    }
}

実行結果

[リンゴ, みかん, バナナ]
リンゴ
みかん
バナナ

解説
始めにコメント(1)部分のインスタンス生成です。セットもリストと同様、ジェネリクス指定を使って格納するインスタンスの型を決定します。

次にコメント(2)部分の要素の追加です。こちらもリストと同様です。addメソッドを使ってインスタンスをセットに追加することができます。

コメント(3)の部分では、HashSetのインスタンスを直接System.out.printlnで表示しています。これにより実行結果では[リンゴ,みかん,バナナ]が表示されています。これは、セットが保持しているインスタンスの内容です。

この結果における注目すべき点は、addメソッドにより「バナナ」が2回追加されたにも関わらず、「バナナ」が1つしか存在しないことです。セットは重複した値を保持できないため、このようになります。また、セットは順序の概念を持たないため、表示順序はこのとおりにならない場合があります。

最後にコメント(4)の部分です。セットもリストと同様に、拡張for文を使ってセット内の値を取得することができます。ただしこちらも、表示順は不定となります。

18-3 マップ

最後にマップをご紹介します。マップはキーのペアで情報を保持します。下図のようなイメージです。

マップのイメージ

「キーを指定して値部分を取り出す。」という使い方が基本となるため、キーの値を重複して持つことはできません

実際のプログラムを例に確認しましょう。マップの代表的なクラスであるHashMapを使用します。

プログラム例(Main.java)

import java.util.HashMap;

public class Main {
    public static void main(String[] args) {
        //インスタンスの生成・・・(1)
        HashMap<String, Integer> map = new HashMap<>();
        //要素の追加。キーと値をペアにする・・・(2)
        map.put("リンゴ", 150);
        map.put("みかん", 200);
        map.put("バナナ", 100);
        //キーを指定して値を取り出す・・・(3)
        System.out.println( map.get("みかん") );
    }
}

実行結果

200

解説
コメント(1)のインスタンス生成部分について解説します。マップのインスタンスを生成する際は、ジェネリクス表記を使ってキーと値の型をそれぞれ指定する必要があります。そのため、HashMapの型宣言部分がHashMap<String, Integer>となっています。

Integerはint型の替わりとなるクラスで整数を表す型です。ジェネリクス指定では基本データ型を使用できないため、Integer型を使用しています。

Integer型のような基本データ型の替わりになるクラスを総称して、ラッパー(wrapper)クラスと言います。ラッパークラスについては次節で説明します。

コメント(2)の部分について解説します。ここではマップに情報を追加しています。マップに情報を追加する際はputメソッドを使用します。putメソッドを呼び出す際はput(キー,値)の形で、引数にキーと値を指定します。

最後のコメント(3)部分では、マップに設定した値を取得しています。この際に使用するのはgetメソッドです。getメソッドは引数にキーを指定することで、値を戻り値として返してくれます。プログラム例はmap.get("みかん")となっているため、「みかん」とペアになっている値「200」が戻り値として返されます。その結果、実行結果に200が表示されます。

18-4 ラッパークラス

コレクションを利用する際に用いられるジェネリクス指定は、基本データ型を指定することができません。たとえば整数を管理するArrayListを使いたい場合に、次のように記述するとエラーとなります。

ArrayList<int> list = new ArrayList<>();

ラッパークラス(wrapper class) は、基本データ型の替わりになるものとして用意されたクラスの総称です。ジェネリクス指定のような基本データ型が使えない状況において、代替手段として利用できます。

それぞれの基本データ型に対応したラッパークラスは下表のとおりです。

基本データ型 ラッパークラス
int Integer
long Long
short Short
byte Byte
double Double
float Float
char Character
boolean Boolean

(※ラッパークラスはすべてjava.langパッケージに属しています。)

18-4-1 ラッパークラスの利用

それでは、ラッパークラスを利用するプログラムを見ていきましょう。

プログラム例(Main.java)

public class Main{
    public static void main(String[] args) {
        Integer i1 = Integer.valueOf(10);//(1)
        int i = i1.intValue();//(2)
        System.out.println(i1);
        System.out.println(i);
    }
}

実行結果

10
10

解説
コメント(1)部分の解説です。Integerインスタンスを取得するためには、IntegerクラスのもつvalueOfメソッドを使用します。引数に整数値を指定することで、その数値を保持するIntegerインスタンスを取得することができます。

コメント(2)の部分の解説です。Integerインスタンスからint型の値を取得したい場合は、intValueメソッドを使います。このメソッドを呼び出すと、Integerインスタンス内にもつ値を戻り値として返してくれます。

最後に変数i1,iの値をそれぞれ表示しています。

このようにラッパークラスの持つメソッドを使うことで、ラッパークラス型と基本データ型の値を相互変換することができます(下図)。

ラッパークラスの相互変換

今回はint型とInteger型の相互変換についてご紹介しましたが、他の基本データ型でも同様です。基本データ型からラッパークラス型への変換はすべてvalueOfメソッドを使いますが、ラッパークラス型から基本データ型に変換するメソッドは、下表のようにクラスごとに異なります。

ラッパークラス 変換メソッド
Integer intValue()
Long longValue()
Short shortValue()
Byte byteValue()
Double doubleValue()
Float floatValue()
Character charValue()
Boolean booleanValue()

18-4-2 ラッパークラスへの自動変換

18-4-1では、ラッパークラスの持つメソッドを使って基本データ型との相互変換を行いました。ですが、基本データ型を扱うためにわざわざメソッド呼び出しを行わなければならないのは不便です。

実はこれらの相互変換は、必要に応じて自動的に行われます。次のプログラムを使って、その様子を確認してみましょう。

プログラム例(Main.java)

public class Main{
    public static void main(String[] args) {
        Integer i1 = 10; //int → Integerの自動変換
        int i = i1; //Integer → intの自動変換
        System.out.println(i1);
        System.out.println(i);
    }
}

実行結果

10
10

解説
3行目ではint型の値10をInteger型の変数i1に代入しています。型が異なるので、本来はそのまま代入できませんが、自動変換のしくみにより代入が可能となっています。

4行目では変数i1をint型の変数iに直接代入しています。こちらも型が異なるので、本来はそのまま代入できませんが、自動変換のしくみにより代入が可能となっています。

基本データ型からラッパークラス型に自動変換されるしくみをオートボクシング(Auto Boxing)、ラッパークラス型から基本データ型に自動変換されるしくみをアンボクシング(UnBoxing)と言います。

オートボクシング

Auto Boxingを直訳すると「自動で箱に入れる」となります。インスタンスという箱の中に基本データ型の値を自動で入れてしまうイメージです。

18-4-3 ラッパークラスの活用

それでは最後にラッパークラスを活用して、整数を保持するリストを作成してみましょう。プログラム例を示します。

プログラム例(Main.java)

import java.util.ArrayList;

public class Main{
    public static void main(String[] args) {
        //リストの生成
        ArrayList<Integer> list = new ArrayList<>();
        //値の追加・・・(1)
        list.add(5);
        list.add(8);
        list.add(12);
        //リストの内容の表示・・・(2)
        System.out.println(list);
    }
}

実行結果

[5, 8, 12]

解説
ジェネリクスにIntegerを指定して、ArrayListを生成しています。

コメント(1)部分のように、addメソッドで値を追加する際は、Integerインスタンスでなく直接int型の値を設定することができます。

コメント(2)ではリスト内の値を一覧表示しています。実行結果のような表示となります。ラッパークラスを使って、int型の値をリストに格納することができました。

コレクションについての説明は以上となります。各コレクションクラスにはご紹介したもの以外にも数多くのメソッドがあります。APIリファレンスやインターネットの情報を参考に、便利に活用してみましょう。

タイトルとURLをコピーしました