値の列

今回の内容

今回はプログラムで多数の値を取り扱うための仕組みである「配列」について紹介します。これまでに紹介した「変数」は、基本的に1つの値しか記憶させられません。そのため、たとえばオセロの盤などをプログラム上で表す場合には、64個の変数を用意したうえで条件分岐などを駆使してそれぞれのマスを取り扱うことになります。

これら複数の値をひとかたまりのデータとしてプログラムから取り扱うには、今回紹介する配列が便利です。1つの配列に複数の値を記憶させて、プログラムから場所を指定してそれぞれの値を利用できます。

今回の作業

今回の例題、練習問題、課題は以下のパッケージに作成してください。

パッケージの名前
j1.lesson06

クラスの作成方法については、「クラスを作成する」を参照してください。

配列を利用したプログラミング

配列の生成と参照

配列を使った簡単なプログラムを見てみましょう。

リスト: FirstArray
package j1.lesson06;

import javax.swing.JOptionPane;

public class FirstArray {

    public static void main(String[] args) {
        new FirstArray().start();
    }

    void start() {
        String[] messages = new String[3];
        messages[0] = "おはよう";
        messages[1] = "こんにちは";
        messages[2] = "こんばんは";
        String input = JOptionPane.showInputDialog("表示するメッセージは?(0-2)");
        int number = Integer.parseInt(input);
        JOptionPane.showMessageDialog(null, messages[number]);
    }
}

まず、startメソッドの先頭でこれまでと異なる種類の変数を宣言しています。ここでは「3つの文字列を記憶させられる配列」を作成しています。

リスト: 配列の生成
String[] messages = new String[3];

通常の変数と異なる点は、まず変数の型を指定する個所でString[]というように末尾に角かっこ(かくかっこ、bracket)をつけています。これは宣言する変数が文字列(String)の配列であるということを表しています。次に異なるのが変数宣言の = 以降の右側です。これは「3つの文字列を記憶させられる配列を生成する」という意味を持っていて、この3という値を64にすれば、64個の文字列を記憶できる配列を生成します。

配列を生成したら、次に配列の各要素に文字列を記憶させています。先ほど宣言したmessageという配列のための変数の名前に、[<要素の位置>]という指定を加えて文字列を代入しています。

リスト: 配列要素の設定
messages[0] = "おはよう";
messages[1] = "こんにちは";
messages[2] = "こんばんは";

要素の位置を0番目から指定しているのは、Javaの配列では要素の位置が0番目から開始するためです。そこから3要素分なので、0、1、2と順番に文字列を記憶させていっています。配列の要素が64個ならば、ここには[0]から[63]までが指定できます。このような要素の位置のことを「配列のインデックス(索引)」と呼びます。

図: 配列の構造とインデックス

最後に、「messages[number]」という書き方で配列の要素から値をコピーして表示しています。たとえばnumberが1であるときには、配列の1番目の要素(messages[1])から「こんにちは」という文字列を取り出して表示します。

リスト: 配列要素の利用
JOptionPane.showMessageDialog(null, messages[number]);
図: 配列要素の参照

以上が配列の簡単な利用方法です。条件分岐などを利用せずに、複数の値から1つを選んで表示することができます。次の項ではもう少し詳しく配列を紹介します。

練習: 配列の生成と参照

作成するクラスの名前
FiveMessages

0から4までの値を入力して、入力された値によって表示するメッセージを返すプログラムを書きなさい。

ただし、FirstArray.javaのプログラムを参考に、5種類のメッセージを配列で利用できるようにすること。

配列の構造

次のプログラムを見てみましょう。実行すると何が表示されるでしょうか。

リスト: StringArray
package j1.lesson06;

import javax.swing.JOptionPane;

public class StringArray {

    public static void main(String[] args) {
        new StringArray().start();
    }

    void start() {
        String[] messages = new String[5];
        messages[0] = "おはよう";
        messages[1] = "こんにちは";
        messages[2] = "こんばんは";
        messages[3] = "さようなら";
        messages[4] = "おやすみなさい";
        JOptionPane.showMessageDialog(null, "messages[0]: " + messages[0]);
        JOptionPane.showMessageDialog(null, "messages[1]: " + messages[1]);
        JOptionPane.showMessageDialog(null, "messages[2]: " + messages[2]);
        JOptionPane.showMessageDialog(null, "messages[3]: " + messages[3]);
        JOptionPane.showMessageDialog(null, "messages[4]: " + messages[4]);
    }
}

これは5個の要素を持つ配列の中身を、インデックスが小さいものから順にすべて表示するプログラムです。つまり、プログラム中に出てくるmessagesという変数には、次のような配列が記憶されています。

インデックス 記憶させた値
0 おはよう
1 こんにちは
2 こんばんは
3 さようなら
4 おやすみなさい

このように、配列は値の一覧のような構造を持っていて、それぞれの値には0番からのインデックスがつけられています。プログラム中のmessagesという変数はこの一覧を丸ごと記憶しているように使え、個々の値を利用する際にはmessages[2]のように対象のインデックスを併せて指定します。

ここまでに紹介した配列は文字列の配列のみでしたが、その他にも整数(int)の配列や実数(double)の配列なども利用できます。変数の宣言や、配列の生成時にそれぞれの型を指定します。

int[] <変数の名前> = new int[<配列の長さ>];
double[] <変数の名前> = new double[<配列の長さ>];
String[] <変数の名前> = new String[<配列の長さ>];

配列の個々の要素を利用する場合は、変数の名前の後に[]をつけてその中にインデックスを指定します。インデックスは整数で指定し、配列の最初の要素は0で、その次の要素は1、といった具合にインデックス1ずつ増やしていけば配列のすべての要素を利用できます。

<変数の名前>[<インデックス>]

プログラム中で配列の要素を設定していた個所も、このインデックスを使っています。次のように設定する要素を指定して、変数への代入と同様に = の右側に代入する値を指定します。

<変数の名前>[<インデックス>] = <代入する値>;

練習: 整数配列の図示

作成するクラスの名前
IntArray

下記のプログラムのstartメソッドでは、arrayという変数に配列を格納し、各要素を初期化したのちにそれぞれ表示している。表示される内容を元に、配列の中身を図示しなさい。

リスト: IntArray
package j1.lesson06;

import javax.swing.JOptionPane;

public class IntArray {

    public static void main(String[] args) {
        new IntArray().start();
    }

    void start() {
        int[] array = new int[3];
        array[1] = 100;
        array[2] = 200;
        array[0] = 300;
        JOptionPane.showMessageDialog(null, "array[0]: " + array[0]);
        JOptionPane.showMessageDialog(null, "array[1]: " + array[1]);
        JOptionPane.showMessageDialog(null, "array[2]: " + array[2]);
    }
}

練習: 実数配列の図示

作成するクラスの名前
DoubleArray

下記のプログラムのstartメソッドでは、arrayという変数に配列を格納し、各要素を初期化したのちにそれぞれ表示している。表示される内容を元に、配列の中身を図示しなさい。

リスト: DoubleArray
package j1.lesson06;

import javax.swing.JOptionPane;

public class DoubleArray {

    public static void main(String[] args) {
        new DoubleArray().start();
    }

    void start() {
        double[] array = new double[4];
        array[3] = 0.1;
        array[2] = 0.2;
        array[1] = 0.3;
        array[0] = 0.4;
        JOptionPane.showMessageDialog(null, "array[0]: " + array[0]);
        JOptionPane.showMessageDialog(null, "array[1]: " + array[1]);
        JOptionPane.showMessageDialog(null, "array[2]: " + array[2]);
        JOptionPane.showMessageDialog(null, "array[3]: " + array[3]);
    }
}

配列を引数に取るメソッド

次のプログラムを見てみましょう。

リスト: Sum
package j1.lesson06;

import javax.swing.JOptionPane;

public class Sum {

    public static void main(String[] args) {
        new Sum().start();
    }

    void start() {
        int[] values = new int[3];
        values[0] = 100;
        values[1] = 200;
        values[2] = 300;
        int total = sum(values);
        JOptionPane.showMessageDialog(null, total);
    }

    int sum(int[] values) {
        return values[0] + values[1] + values[2];
    }
}

ここでは、次のように配列を引数に取るようなメソッドを宣言しています。

リスト: 配列を引数に取るメソッド
int sum(int[] values) {
    return values[0] + values[1] + values[2];
}

上記のように、仮引数を宣言する際に配列の型を指定すると、配列を引数に取るメソッドを宣言できます。このメソッドを起動する際には、次のように配列そのものを実引数に指定します。

リスト: 配列をメソッドの実引数に指定する
int[] values = new int[3];
...
int total = sum(values);

このように、配列の個々の要素だけではなく、配列そのものもプログラム中で値として利用できます。メソッドの起動引数として渡せば、受け取った側はそのまま渡された配列をプログラム中で利用できます。

練習: 配列を引数に取るメソッド

作成するクラスの名前
Select

下記のプログラムを書き換えて、FirstArray と同様の動きをするようにしなさい。ただし、インデックスを入力し、要素を選択する処理はプログラム中のselectメソッド内で行うこと。

リスト: Select
package j1.lesson06;

import javax.swing.JOptionPane;

public class Select {

    public static void main(String[] args) {
        new Select().start();
    }

    void start() {
        String[] messages = new String[3];
        messages[0] = "おはよう";
        messages[1] = "こんにちは";
        messages[2] = "こんばんは";
        _______________________
        JOptionPane.showMessageDialog(null, message);
    }

    String select(______________________) {
        String input = JOptionPane.showInputDialog("要素を選択(0-2)");
        int number = Integer.parseInt(input);
        return messages[number];
    }
}

配列を返すメソッド

引数同様に、配列を返すメソッドも利用可能です。

リスト: NewStringArray
package j1.lesson06;

import javax.swing.JOptionPane;

public class NewStringArray {

    public static void main(String[] args) {
        new NewStringArray().start();
    }

    void start() {
        String[] messages = createMessages();
        String input = JOptionPane.showInputDialog("表示するメッセージは?(0-2)");
        int number = Integer.parseInt(input);
        JOptionPane.showMessageDialog(null, messages[number]);
    }

    String[] createMessages() {
        String[] messages = new String[3];
        messages[0] = "おはよう";
        messages[1] = "こんにちは";
        messages[2] = "こんばんは";
        return messages;
    }
}

ここでは、戻り値の型を指定する個所に配列を表す型を指定しています。

リスト: 配列を返すメソッド
String[] createMessages() {
    String[] messages = new String[3];
    ...
    return messages;
}

また、return文には生成した配列を記憶する変数をそのまま指定しています。このように指定することで、createMessagesメソッドの中で生成した配列を、下記のように起動元に丸ごと返しています。

リスト: 配列の戻り値を受け取る
String[] messages = createMessages();

起動元では配列を生成する際と同様に、メソッドが返した値を配列型の変数に記憶させています。この配列はすでに起動先のメソッドで要素が設定されているので、返された値をそのまま利用できます。

練習: 配列を返すメソッド

作成するクラスの名前
NewIntArray

下記のプログラムに createValues というメソッドを宣言し、要素数が5の整数配列を生成して返すようにしなさい。

生成する配列の要素は順に100, 200, 300, 400, 500で初期化すること。

リスト: NewIntArray
package j1.lesson06;

import javax.swing.JOptionPane;

public class NewIntArray {

    public static void main(String[] args) {
        new NewIntArray().start();
    }

    void start() {
        int[] array = createValues();
        showValues(array);
    }

    void showValues(int[] array) {
        JOptionPane.showMessageDialog(null, "array[0]: " + array[0]);
        JOptionPane.showMessageDialog(null, "array[1]: " + array[1]);
        JOptionPane.showMessageDialog(null, "array[2]: " + array[2]);
        JOptionPane.showMessageDialog(null, "array[3]: " + array[3]);
        JOptionPane.showMessageDialog(null, "array[4]: " + array[4]);
    }
}

文字列の分解

最後に、少し変わった配列の使い方を紹介します。

リスト: SplitAdd
package j1.lesson06;

import javax.swing.JOptionPane;

public class SplitAdd {

    public static void main(String[] args) {
        new SplitAdd().start();
    }

    void start() {
        String input = JOptionPane.showInputDialog("カンマ区切りの数値列");
        String[] values = input.split(",");
        if (values.length != 2) {
            JOptionPane.showMessageDialog(null, "数値を2つ入力してください");
        }
        else {
            int a = Integer.parseInt(values[0]);
            int b = Integer.parseInt(values[1]);
            JOptionPane.showMessageDialog(null, "合計は" + (a + b));
        }
    }
}

このプログラムでは、ダイアログに入力された文字列に対して「.split(",")」という操作をしています。

リスト: 文字列の分解
String input = JOptionPane.showInputDialog("カンマ区切りの数値列");
String[] values = input.split(",");

これは「文字列を , (カンマ)ごとに分解した配列を生成する」という機能があります。たとえば"100,200"と入力された場合には"100"と"200"という値を順に記憶する配列が返されます。

図: 文字列の分解

今回は自分で配列を生成しないため、配列の長さは実行するたびに変わってしまいます。このため、プログラムでは、「.length」という操作で配列の長さを取得しています。今回はカンマ区切りの2つの整数を利用するプログラムなので、"100,200,300"のように2つ以外に区切れてしまう場合にはif文で判定してエラーメッセージを表示しています。

リスト: 配列の長さ
if (values.length != 2) {
    JOptionPane.showMessageDialog(null, "数値を2つ入力してください");
}
else { ...

残りのelseの部分では、配列の要素が2個という前提で命令を書いています。内容は単純で、2つの文字列を整数に変換したのち、合計をダイアログに表示しているだけです。

リスト: 分解した文字列の利用
...
else {
    int a = Integer.parseInt(values[0]);
    int b = Integer.parseInt(values[1]);
    JOptionPane.showMessageDialog(null, "合計は" + (a + b));
}

まとめると、カンマ区切りの入力を分解するにはsplitを利用し、返ってきた配列の長さを利用するにはlengthを利用できます。

命令 結果
<文字列>.split(“,”) カンマごとに分解された文字列の配列
<配列>.length 配列の長さ

このようにすると、2つ以上の値をダイアログで入力するのが少し楽になります。ただし、splitから返ってきた配列の長さはデータによって変わることがあるため、lengthで配列の長さを確認してから利用しましょう。

練習: 文字列の分解

作成するクラスの名前
Average

カンマ区切りで3つの整数を入力し、それらの平均値を表示するプログラムを書きなさい。ただし、入力される整数の個数が3以外の場合はエラーを表示すること。たとえば「60,40,50」と入力すると「平均は50です」と表示し、「1,2,3,4」と入力すると「数値を3つ入力してください」と表示する。

まとめ

今回はプログラムで多数の値を取り扱うための仕組みとして、「配列」というものを紹介しました。配列にはこれまでに紹介した整数や実数、または文字列などの値を複数記憶させられます。

リスト: 配列の生成と要素の設定
int[] array = new int[10];
array[0] = 100;
array[1] = 200;
...

配列をプログラムから利用するには、まず配列を生成して変数に記憶させます。配列を生成する際には、配列が記憶できる値の種類と、長さ(記憶できる値の個数)を指定します。

int[] <変数の名前> = new int[<配列の長さ>];
double[] <変数の名前> = new double[<配列の長さ>];
String[] <変数の名前> = new String[<配列の長さ>];

配列に記憶させた個々の値を利用するには、変数名の後に角かっこでインデックスを指定します。

リスト: 配列要素のインデックスの指定
int element = array[5];

インデックスは整数で指定し、配列の最初の要素を参照する場合には0、最後の要素を参照する場合には(配列の長さ – 1)を指定します。この配列の長さは、変数名の後に".length"と指定すればプログラム中から利用できます。

図: 配列の構造とインデックス

生成した配列を他のメソッドで利用する場合、メソッドの引数として受け渡せます。このとき、仮引数の型には配列型を指定します。

リスト: 配列を受け取るメソッド
void show(int[] array) {
    JOptionPane.showMessageDialog(null, array[0]);
}

同様に、生成した配列を起動元に返すこともできます。こちらは戻り値の型に配列型を指定します。

リスト: 配列を返すメソッド
String[] create() {
    String[] array = new String[10];
    ...
    return array;
}

つまり、int[], double[], String[]などの配列を表す型は、int, double, Stringなどのこれまでの型と同様に取り合え使えます。

以上が今回のまとめです。複数の値を持つデータをプログラムから操作できるようになったので、多数のデータをプログラムで取り扱いやすくなりました。