読み込み中...

Javaで学ぶ多次元配列!初心者から上級者への15ステップ

Java多次元配列の作成と利用方法を学ぶためのステップバイステップガイド Java
この記事は約24分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Javaの多次元配列は、表形式の値、座標、行列、階層化されたデータを扱うときに使われる配列構造です。プログラム初心者がつまずきやすいのは、int[][]の見た目よりも、行と列のどちらを先に考えるか、array.lengtharray[i].lengthをどう使い分けるかという点になります。

そのため、宣言、初期化、代入、参照、ループ処理、例外への対処を一つずつ結び付けて理解すると、Javaの多次元配列の使い方が整理できます。サンプルコードは基本形からカスタマイズ例まで残し、各<pre>直後に期待される出力や期待される状態を示するのが基本です。

動作確認環境
  • Java SE 21 / javac 21
  • 標準ライブラリ: java.util.Arrays / java.util.ArrayList
📖 この記事で学べること
  • Javaの多次元配列を宣言し、初期化する使い方
  • for文と拡張for文で全要素を扱うテクニック
  • 二次元配列、三次元配列、行列処理のサンプルコード
  • ArrayListと組み合わせたカスタマイズの考え方
  • 範囲外アクセスやnullによる注意点と対処法

Javaと多次元配列の基本

Javaで多次元配列を扱う結論は、配列の配列として読むことです。int[][] scoresは、int[]を要素に持つ配列と考えると、行ごとに長さが違う配列も自然に理解できます。

データ型[][] 配列名;

結果: 期待される状態は、二次元配列を参照する変数の宣言だけが行われ、配列本体はまだ作られていない状態です。

これに対して、配列本体を作るにはnewを使います。公式ドキュメントによれば、Javaの配列はオブジェクトであり、詳しい仕様はJava Language Specification: Arraysで確認できるのが目安です。

データ型[][] 配列名 = new データ型[行数][列数];

結果: 期待される状態は、指定した行数と列数を持つ二次元配列が作成され、数値型なら各要素が0で初期化される状態です。

その構造を具体化すると、int型の3行3列は次の形になります。プログラム初心者は、[0][0]が左上、[2][2]が右下という位置関係から覚えると扱いやすくなります。

int[][] multiArray = new int[3][3];

結果: 期待される状態は、multiArrayに3行3列のint配列が入り、全要素が0の初期値を持つことです。

このとき、値を入れる位置は行インデックス列インデックスの組み合わせで決まりますし、ここがポイントです。multiArray[0][1]なら、最初の行にある2番目の列を指します。

multiArray[0][0] = 1;
multiArray[0][1] = 2;
multiArray[0][2] = 3;

結果: 期待される状態は、multiArrayの最初の行に123が順に格納されることです。

Javaとは

Javaは、クラスを中心に処理を組み立てるオブジェクト指向言語です。classpublicstaticvoidmainなどの構文を使い、標準ライブラリと組み合わせてアプリケーションを作ります。

一般に、Javaの配列は型が固定され、int[]にはintString[]にはStringだけを入れます。その型安全性があるため、データ型の不一致はコンパイル時に見つかりやすいと言えますが、これは押さえたい点です。

Javaの基本構文に不安がある場合は、配列へ進む前にJava List型完全ガイドでコレクションの考え方を押さえると、ArrayListとの違いも整理できます。

多次元配列の基本概念

多次元配列は、配列の中に配列を入れる構造です。二次元配列なら行と列、三次元配列なら層、行、列のように考えられます。

その構造は、表データ、ゲーム盤、座標、画像のピクセル、成績表のように、複数の軸を持つデータと相性があるのがポイントです。一方、単純な一覧だけなら一次元配列やListのほうが読みやすい場面もあります。

項目主な書き方用途注意点
一次元配列int[] a単純な一覧列や行の概念は自分で補う
二次元配列int[][] a表、行列、盤面[行][列]の順序をそろえる
三次元配列int[][][] a層を持つデータ読みやすさが落ちやすい
ジャグ配列new int[2][]行ごとに列数が違う表各行の初期化が必要
コレクション併用ArrayList<int[]>行数を増減したい処理固定長配列との違いを意識する

この早見表の中で特に押さえたいのは、二次元配列が必ず長方形になるとは限らない点です。Javaではnew int[2][]のように列数を後から決められるため、行ごとに長さが異なる構造も作れます。

一次元配列との違い

一次元配列は、array[0]array[1]のように一つの番号で要素を取り出します。多次元配列ではarray[0][1]のように、外側の配列から内側の配列へ順にたどりますし、これが一つの目安です。

その違いにより、ループも一重ではなく二重や三重になる場合があります。プログラム初心者は、外側のforが行を動かし、内側のforが列を動かすと覚えると、サンプルコードを読みやすくなります。

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

多次元配列の宣言では、[]の数が次元数を表するのが一般的です。int[][]は二次元、int[][][]は三次元になり、String[][]なら文字列を並べる表を作れます。

具体的には、new int[3][3]で固定サイズを確保する方法と、波括弧で値を並べる方法があります。値が決まっているなら初期化子を使うほうが短く、後から計算して入れるならnewで枠を作るほうが自然です。

💡 Tips: int[][] dataint[]を要素に持つ配列として読むと、data.lengthが行数、data[i].lengthが各行の列数を返す理由が分かりやすくなるのが現実的です。

多次元配列の作り方

Javaで多次元配列を作る使い方は、固定サイズを先に用意する方法と、初期値をまとめて書く方法に分かれます。どちらも同じint[][]を扱いますが、読みやすさと変更しやすさに違いがあります。

基本的な作成方法

固定サイズの配列は、行数と列数が処理前に決まっているときに向きますが、覚えておくと役立つでしょう。座席表や3×3の盤面のように大きさが変わらないデータでは、new int[3][3]の形が読みやすくなります。

宣言と初期化

宣言と初期化を分けると、変数名を先に決めてから配列本体を作れます。一方、同じ行で書くと、変数と配列の関係が近くなり、短いサンプルコードでは把握しやすい形になると整理できます。

int[][] multiArray = new int[3][3];

結果: 期待される状態は、3×3の二次元配列が生成され、multiArray[0][0]からmultiArray[2][2]まで参照できることです。

これに対し、値を最初から持たせる場合は初期化子を使います。{1, 2, 3}が1行分を表し、それを外側の{}で包むと二次元配列になります。

int[][] multiArray = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

結果: 期待される状態は、multiArray[0][0]1multiArray[2][2]9が入った3×3の配列です。

その書き方は、学習用のデータや固定の設定値に向いていると理解できます。ただし、入力ファイルやユーザー操作で値が変わる処理では、for文やメソッドで代入する構成のほうがカスタマイズしやすくなります。

要素へのアクセス方法

要素へアクセスするときは、[行][列]の順でインデックスを並べます。インデックスは0から始まるため、3行3列の最後は[2][2]になると覚えるとよいでしょう。

int[][] multiArray = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};
System.out.println(multiArray[0][0]); // 出力:1
System.out.println(multiArray[2][2]); // 出力:9

結果: 期待される出力は、1行目に1、2行目に9が表示される形です。

このとき、multiArray[0]だけなら最初の行を表すint[]です。multiArray[0][0]まで書いて初めて、行の中にある一つのint値を取り出せます。

詳細な使い方

多次元配列の詳細な使い方では、ループ、メソッド化、戻り値の扱いが中心になります。Javaの配列はlengthを持つため、固定の数値を直接書かずに配列自身の長さを参照するテクニックが実用的です。

ループを使用したデータの取り扱い

二次元配列の全要素を処理するには、外側のforで行、内側のforで列を走査すると考えられます。列数が行ごとに違う場合もあるため、内側ではarray[i].lengthを使うのが安全です。

int[][] array = {{1,2,3}, {4,5,6}, {7,8,9}};
for(int i = 0; i < array.length; i++) {
    for(int j = 0; j < array[i].length; j++) {
        System.out.println(array[i][j]);
    }
}

結果: 期待される出力は、1から9までの数値が1行ずつ順に表示される形です。

このサンプルコードでは、固定値の3ではなくarray.lengtharray[i].lengthを使っています。そのため、行数や列数が変わってもループ条件を直す箇所が少なくなります。

メソッドとしての利用

同じ合計処理を複数箇所に書くと、変更が必要になったときに修正漏れが起きやすくなると言えるでしょう。そのため、二次元配列を引数に取り、計算結果をreturnするメソッドへ切り出すと保守しやすくなります。

public static int sumOfArray(int[][] array) {
    int sum = 0;
    for(int i = 0; i < array.length; i++) {
        for(int j = 0; j < array[i].length; j++) {
            sum += array[i][j];
        }
    }
    return sum;
}

int[][] sampleArray = {{1,2,3}, {4,5,6}, {7,8,9}};
int result = sumOfArray(sampleArray);
System.out.println(result);

結果: 期待される出力は45です。sumOfArrayが全要素を加算し、System.out.printlnで合計値を表示します。

同様に、最大値、平均値、特定値の検索もメソッド化できます。Javaのメソッド引数は配列参照を受け取るため、読み取りだけなら呼び出し元の変数名を意識せずに処理できるのが基本です。

詳細なカスタマイズ方法

配列は作成後に長さを変えられないため、行数を増やしたい処理では別の構造を検討します。一般的に、行を追加したいならArrayList<int[]>を使い、各行の中身はint[]として保持する方法があります。

公式APIの詳細はArrayList API documentationにまとまっているのが目安です。addgetsizeを使うと、固定長配列とは違うカスタマイズが可能になります。

配列の動的作成

動的に行を増やすサンプルコードでは、ArrayListの要素としてint[]を追加します。プログラム初心者は、これは厳密には配列そのものを伸ばしているのではなく、配列を入れるリストを伸ばしていると理解すると混乱を避けられますし、ここを基本と考えるとよいでしょう。

import java.util.ArrayList;

public class DynamicMultiArray {
    public static void main(String[] args) {
        ArrayList<int[]> dynamicMultiArray = new ArrayList<>();
        dynamicMultiArray.add(new int[]{1, 2, 3});
        dynamicMultiArray.add(new int[]{4, 5, 6, 7});

        for(int[] row : dynamicMultiArray) {
            for(int num : row) {
                System.out.print(num + " ");
            }
            System.out.println();
        }
    }
}

結果: 期待される出力は、1行目に1 2 3、2行目に4 5 6 7が表示される形です。

その処理では、dynamicMultiArrayが行の集合を持ち、rowが各行の配列を受け取ります。拡張for文はインデックスが不要な読み取り処理に向き、行ごとの列数が異なっていても自然に回せます。

多次元配列とコレクション

多次元配列とコレクションを組み合わせるテクニックは、データ数が後から変わる処理で役立ちますし、ここがポイントです。たとえば、CSVの行を読み込むたびにint[]へ変換し、ArrayListへ追加する構成が考えられます。

import java.util.ArrayList;

public class MultiArrayWithCollection {
    public static void main(String[] args) {
        ArrayList<int[]> listWithMultiArray = new ArrayList<>();
        listWithMultiArray.add(new int[]{1, 2, 3});
        listWithMultiArray.add(new int[]{4, 5, 6, 7});

        for(int[] array : listWithMultiArray) {
            for(int value : array) {
                System.out.print(value + " ");
            }
            System.out.println();
        }
    }
}

結果: 期待される出力は、1 2 34 5 6 7が別々の行として表示される形です。

これらの構成では、ArrayListが行の増減を担当し、int[]が各行の値を保持します。一方、頻繁に列の追加削除も行うなら、ArrayList<ArrayList<Integer>>のような構造も候補になります。

⚠️ 注意: intはプリミティブ型のため、ArrayList<int>とは書けません。要素を個別にリスト化する場合はIntegerを使いるのがポイントです。

多次元配列のサンプルコードと説明

多次元配列のサンプルコードは、配列を作るだけでなく、値を入れ、取り出し、並べ替え、行列として変換する流れで読むと理解が進みます。Javaの文法に慣れていない場合は、Javaエスケープ処理のガイドも合わせて確認すると、文字列出力の読み方が整理できます。

基本的なサンプルコード

基本のサンプルコードでは、二次元配列と三次元配列を扱いるのが一般的です。どちらもnewで領域を作り、for文で全要素に触れるという流れは共通しています。

二次元配列の作成と利用

二次元配列は、行と列で値を管理する典型的な形です。次のサンプルコードでは、twoDimensionalArrayに1から9までを代入し、二重ループで表示します。

int[][] twoDimensionalArray = new int[3][3];

// 要素への代入
twoDimensionalArray[0][0] = 1;
twoDimensionalArray[0][1] = 2;
twoDimensionalArray[0][2] = 3;
twoDimensionalArray[1][0] = 4;
twoDimensionalArray[1][1] = 5;
twoDimensionalArray[1][2] = 6;
twoDimensionalArray[2][0] = 7;
twoDimensionalArray[2][1] = 8;
twoDimensionalArray[2][2] = 9;

// 配列の内容を表示
for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
        System.out.print(twoDimensionalArray[i][j] + " ");
    }
    System.out.println();
}

結果: 期待される出力は、3行に分かれて1 2 34 5 67 8 9が表示される形です。

1 2 3 
4 5 6 
7 8 9 

結果: 期待される表示例は、二次元配列の各行がそのまま1行ずつ並ぶ形式です。

この例ではiが行、jが列を表します。カスタマイズするなら、3twoDimensionalArray.lengthtwoDimensionalArray[i].lengthに置き換えると、配列サイズの変更に対応しやすくなります。

三次元配列の作成と利用

三次元配列は、層、行、列のように軸が増えた構造です。プログラム初心者には少し読みにくくなりますが、[層][行][列]の順に意味を決めておくと混乱を減らせますが、これは押さえたい点です。

int[][][] threeDimensionalArray = new int[2][2][2];

// 要素への代入
threeDimensionalArray[0][0][0] = 1;
threeDimensionalArray[0][0][1] = 2;
threeDimensionalArray[0][1][0] = 3;
threeDimensionalArray[0][1][1] = 4;
threeDimensionalArray[1][0][0] = 5;
threeDimensionalArray[1][0][1] = 6;
threeDimensionalArray[1][1][0] = 7;
threeDimensionalArray[1][1][1] = 8;

// 配列の内容を表示
for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 2; j++) {
        for (int k = 0; k < 2; k++) {
            System.out.print(threeDimensionalArray[i][j][k] + " ");
        }
        System.out.println();
    }
    System.out.println();
}

結果: 期待される出力は、1つ目の層に1 23 4、2つ目の層に5 67 8が表示される形です。

1 2 
3 4 

5 6 
7 8 

結果: 期待される表示例は、空行で層の区切りを表しながら、各層の2×2データを並べる形式です。

そのまま三重ループを増やしていくと、処理の意図が見えにくくなる場合があります。必要に応じてprintLayerのようなメソッドに分けると、表示処理とデータ作成を切り離せます。

応用例とサンプルコード

応用例では、行ごとのソートと行列の転置を扱いるのが現実的です。どちらも多次元配列の値を加工するテクニックであり、データ整理や数値処理の入口になります。

データのソート

行ごとに並べ替える場合は、標準ライブラリのArrays.sortを各行へ適用します。ArraysのAPIはArrays API documentationで確認できると整理できます。

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[][] data = {
            {3, 5, 1},
            {10, 2, 8},
            {6, 4, 7}
        };

        for(int[] row : data) {
            Arrays.sort(row);
        }

        for(int[] row : data) {
            for(int num : row) {
                System.out.print(num + " ");
            }
            System.out.println();
        }
    }
}

結果: 期待される出力は、各行だけが昇順に並び替わり、行同士の順序は変わらない形です。

1 3 5 
2 8 10 
4 6 7 

結果: 期待される表示例は、{3, 5, 1}1 3 5へ変わるように、各行が個別に整列された形式です。

一方、表全体を一つの集合として並べ替えたい場合は、いったん一次元のリストへ展開する設計が必要になります。行単位のソートと全体ソートは目的が違うため、仕様を決めてからコードに落とし込むのが現実的です。

行列の操作

行列の転置では、元のmatrix[i][j]を新しい配列のtransposedMatrix[j][i]へ入れます。この入れ替えにより、行が列へ、列が行へ変わりますし、これが一つの目安です。

public class Main {
    public static void main(String[] args) {
        int[][] matrix = {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        };

        int[][] transposedMatrix = new int[3][3];

        for(int i = 0; i < 3; i++) {
            for(int j = 0; j < 3; j++) {
                transposedMatrix[j][i] = matrix[i][j];
            }
        }

        for(int[] row : transposedMatrix) {
            for(int num : row) {
                System.out.print(num + " ");
            }
            System.out.println();
        }
    }
}

結果: 期待される出力は、元の列が新しい行として並び、1 4 7から始まる行列です。

1 4 7 
2 5 8 
3 6 9 

結果: 期待される表示例は、3×3の行列が転置され、対角線を基準に値の位置が入れ替わった形式です。

この処理を長方形の行列へ広げる場合は、転置先のサイズをnew int[列数][行数]に変えます。たとえば2行3列を転置すると、3行2列の配列が必要になります。

ℹ️ 補足: アノテーションやオーバーライドと組み合わせて設計を広げる場合は、Javaアノテーションの解説Javaオーバーライドのガイドを参照すると、配列処理をクラス設計へ接続しやすくなると理解できます。

多次元配列の注意点と対処法

Javaの多次元配列には、型の不一致、範囲外アクセス、未初期化の行という注意点があります。これらはコンパイルエラーや例外として表れやすいため、原因と対処法を分けて押さえると修正が早くなります。

データ型の一致

Javaの配列は、一度決めた要素型を途中で変えられません。int[][]Stringを入れようとすると、型が合わないためコンパイルエラーになると覚えるとよいでしょう。

int[][] array = new int[2][2];
array[0][0] = 1;
array[0][1] = "string"; // コンパイルエラー

結果: 期待される状態は、Stringint配列へ代入できないため、コンパイル時に型不一致として扱われることです。

その対処法は、配列の目的に合わせて型をそろえることです。数値計算ならint[][]double[][]、文字列の表ならString[][]、異なる型をまとめたいならクラスを作ってRecordや通常のオブジェクト配列にする設計が考えられます。

配列の範囲外アクセス

配列の範囲外アクセスは、存在しないインデックスを参照したときに起きます。JavaではArrayIndexOutOfBoundsExceptionが発生し、処理が例外として中断されますが、覚えておくと役立つでしょう。

int[][] array = new int[2][2];
array[0][0] = 1;
array[2][0] = 2; // ArrayIndexOutOfBoundsException

結果: 期待される状態は、arrayの有効な行インデックスが01だけのため、array[2][0]で範囲外アクセスになることです。

この注意点への対処では、固定値ではなくarray.lengtharray[i].lengthを使います。特にジャグ配列では行ごとに列数が違うため、内側の長さを毎回確認するテクニックが欠かせません。

nullポインタ例外

列数を後から決める形でnew int[2][]と書くと、外側の配列だけが作られます。内側のint[]はまだ存在しないため、初期化していない行へアクセスするとNullPointerExceptionにつながりますし、ここを基本と考えるとよいでしょう。

int[][] array = new int[2][];
array[0] = new int[2];
array[0][0] = 1;
System.out.println(array[1][0]); // NullPointerException

結果: 期待される状態は、array[1]nullのままなので、array[1][0]へ進もうとした時点でNullPointerExceptionになることです。

その対処法は、各行を使う前にnew int[列数]で初期化することです。入力データから行を作る場合も、nullチェックや初期化済みかどうかの確認を入れると、例外の原因を絞り込みやすくなります。

⚠️ 注意: 例外を避けるためにtrycatchで包むだけでは、根本原因の修正にならない場合があります。範囲外ならインデックス条件、nullなら初期化漏れを直すのが基本になると考えられます。

実際の開発では、うるう年の表や月別集計のような表データにも二次元配列の考え方を応用できます。日付ロジックと組み合わせる場合は、Javaでうるう年を判定する解説も参考になります。

まとめ

Javaの多次元配列は、int[][]String[][]のように配列を入れ子にして、行と列を持つデータを表すると言えるでしょう。宣言、初期化、代入、参照の流れを押さえると、プログラム初心者でも表形式のデータを扱いやすくなります。

これらの使い方で中心になるのは、array.lengtharray[i].lengthの使い分けです。固定の数値をループ条件に書くより、配列自身の長さを参照したほうが、列数の違いやカスタマイズに対応しやすくなります。

多次元配列のサンプルコードでは、二次元配列、三次元配列、ソート、転置、ArrayListとの併用を扱いました。どのテクニックでも、行を表す変数と列を表す変数の役割をそろえると、読み手が処理を追いやすくなるのが基本です。

注意点として、型の不一致、範囲外アクセス、未初期化の行によるNullPointerExceptionがあります。エラーが出たときは、intStringの混在、[2]のような範囲外の番号、nullの行が残っていないかを順に確認すると原因へ近づけます。

そのうえで、配列の長さが固定でよい処理は多次元配列、行数や列数を増減したい処理はArrayListなどのコレクションを選ぶと、Javaのコードは整理しやすくなるのが目安です。多次元配列を使うべき場面と別構造を選ぶ場面を分けることが、実用的な設計につながります。

関連記事

著者: Japanシーモア編集部

Japanシーモアは、Web/IoT/APP/SYS 分野のプログラミング情報を体系的に提供するメディアです。本記事は編集部による執筆とAI支援を組み合わせて制作し、公開前に編集部が校正しています。誤りや改善案がございましたらお問い合わせよりご連絡ください。

※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。