【Java】Javaの多次元配列の使い方:2次元配列を中心に解説

Java

こんにちは、かつコーチです。

配列の基本を理解したら、次に出てくるのが多次元配列(配列の中にさらに配列を格納したデータ構造)です。
表形式のデータやマス目状のデータを扱う場面でよく登場します。
この記事では2次元配列を中心に、宣言方法・走査方法・ハマりやすいポイントを解説します。

多次元配列とは?

なぜ多次元配列が必要なのか

例えば「3クラス分、各クラス5人分のテストの点数」を扱いたいとき、1次元配列だけでは表現しづらくなります。
このような表形式・グリッド状のデータを表すために、配列の中に配列を入れる多次元配列を使います。

Javaの多次元配列は「配列の配列」

Javaの2次元配列は、厳密には「配列を要素として持つ配列」です。
言い換えると、各行の配列は独立しており、行ごとに異なる要素数を持たせることもできます。
これをジャグ配列(各行の長さが揃っていない配列)と呼びます。

基本の書き方:2次元配列

2次元配列の宣言と初期化

public class Main {
    public static void main(String[] args) {
        // 3クラス分、各クラス3人分の点数
        int[][] scores = {
            {80, 90, 70},
            {60, 75, 85},
            {95, 88, 92}
        };

        System.out.println(scores[0][1]); // 1クラス目の2人目 -> 90
        System.out.println(scores[2][0]); // 3クラス目の1人目 -> 95
    }
}

scores[行][列]のように2つの添字を指定してアクセスします。
行方向がクラス、列方向が生徒番号、というように意味を決めて設計すると読みやすくなります。

newを使った2次元配列の作成

int[][] grid = new int[3][4]; // 3行4列の配列(すべて0で初期化される)

for (int i = 0; i < grid.length; i++) {
    for (int j = 0; j < grid[i].length; j++) {
        grid[i][j] = i * 4 + j;
    }
}

grid.lengthは行数、grid[i].lengthはi行目の列数を表します。
2次元配列を走査するときは、この2つのlengthを組み合わせて二重のfor文を書くのが基本パターンです。

よくあるつまずきポイント・エラー対処

添字の順番を取り違えたハマりどころ

私が実際に手を動かしたときにやってしまったミスがこちらです。

❌ Before
int[][] scores = {
    {80, 90, 70},
    {60, 75, 85}
};

// 「1人目の2クラス分の点数」のつもりで書いたが実際は逆
System.out.println(scores[1][0]);

「1人目、2クラス目」のつもりでscores[1][0]と書きましたが、実際には「2クラス目の1人目」という意味になり、想定と異なる値を取得していました。
2次元配列は「外側が行、内側が列」という順序を常に意識しないと、意図と逆の要素を読んでしまいます。

✅ After
// 変数名で行・列の意味を明示しておくと間違えにくい
int classIndex = 1;   // 2クラス目
int studentIndex = 0; // 1人目
System.out.println(scores[classIndex][studentIndex]);

添字をそのまま数字で書くのではなく、意味の分かる変数名に置き換えることで、どちらが行でどちらが列かを混同しにくくなります。

行ごとに列数が異なるジャグ配列でのNullPointerException

❌ Before
int[][] jagged = new int[3][];
jagged[0] = new int[]{1, 2, 3};
jagged[1] = new int[]{4, 5};
// jagged[2] を初期化し忘れる

for (int[] row : jagged) {
    for (int value : row) { // NullPointerException
        System.out.println(value);
    }
}

new int[3][]で作った時点では、各行はまだnullのままです。
jagged[2]を初期化せずに走査しようとすると、rownullとなりNullPointerExceptionが発生します。

✅ After
int[][] jagged = new int[3][];
jagged[0] = new int[]{1, 2, 3};
jagged[1] = new int[]{4, 5};
jagged[2] = new int[]{6};

for (int[] row : jagged) {
    for (int value : row) {
        System.out.println(value);
    }
}

行ごとに長さが異なる配列を使う場合は、すべての行を初期化し終えたかを必ず確認しましょう。

応用・一歩先の使い方

Arrays.deepToStringで多次元配列を確認する

import java.util.Arrays;

int[][] scores = {
    {80, 90, 70},
    {60, 75, 85}
};

System.out.println(Arrays.deepToString(scores));
// [[80, 90, 70], [60, 75, 85]]

1次元配列ではArrays.toStringを使いましたが、多次元配列の中身を表示したい場合はArrays.deepToStringを使います。
toStringだと内側の配列がハッシュ値の羅列になってしまうため、デバッグ時にはこちらを使い分けましょう。

まとめ

この記事のポイント

  • Javaの2次元配列は「配列を要素に持つ配列」で、行ごとに要素数を変えることもできる
  • array[行][列]の順序を混同すると意図と逆の要素を取得してしまう
  • ジャグ配列は行ごとの初期化漏れがNullPointerExceptionの原因になりやすい
  • 多次元配列の中身の確認にはArrays.deepToStringを使う

次に読むべき記事

  • 配列の基本:宣言・初期化・要素アクセス
  • Stringの基本:作成・比較・連結

タグ: Java, 中級者向け, 基本文法

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