MEDIA

メディア

  1. TOP
  2. メディア
  3. プログラミング
  4. Java配列(array)完全ガイド|宣言・初期化・ループ・コピー・例外対策

Java配列(array)完全ガイド|宣言・初期化・ループ・コピー・例外対策

まずJavaの配列(array)は、同じデータ型の値をまとめて扱うための基本データ構造です。

さらに繰り返し処理や検索・ソートなど、多くの処理の土台になります。

そのため最初に配列を押さえると、学習が迷子になりにくくなります。

この記事では、配列の概念から宣言・生成・初期化、要素操作、ループ処理、コピーやソート、多次元配列、よくある例外までを整理します。

したがってサンプルコードを読みながら「どう書くか」「なぜそうなるか」を理解することを目的に進めます。

Javaの配列とは

まず配列は、複数の値を1つのまとまりとして保持し、インデックスで個々の要素へアクセスできる仕組みです。

例えばテストの点数を人数分持ちたいとき、int変数を人数分用意する代わりに、intの配列にまとめて格納できます。

さらに配列の重要な性質は「作成時に長さが確定し、その後は固定」という点です。

つまり途中で要素数を増減させたい場面では、配列だけで完結させにくいことがあります。

その一方で、固定長であるぶん挙動が単純で、インデックスで素早くアクセスできます。これは入門として理解しやすい強みです。参考:Oracle公式チュートリアル(Arrays)。

配列の特徴とメリット

まず配列の強みは、同じ型のデータをひとまとめにし、ループで一括処理できる点です。

例えば合計、平均、最大値の計算は、配列にしてforで走査するのが定番です。

一方で、配列はサイズ固定という制約があります。

したがって要素数が増減するデータには不向きです。

そのため用途に応じて、配列とArrayListを使い分ける判断が重要になります。

なお、配列とArrayListの使い分けを整理したい場合は、以下の内部リンクもあわせて確認すると理解が早まります。

配列の基本ルール

まず配列でつまずく原因の多くは、インデックスの範囲と型の制約を曖昧にしたまま使ってしまうことです。

しかしルール自体はシンプルで、早い段階で身体に染み込ませると後が楽になります。

インデックスは0から始まり、範囲は0〜length-1

まず配列の要素は、配列名[index]で参照・代入します。

例えば int[] a = {10, 20, 30}; なら、a[0]は10、a[1]は20です。

さらにインデックスは0から始まります。

したがって要素数が3なら有効なインデックスは0〜2で、最後はlength-1になります。

一方で、範囲外のインデックスにアクセスすると ArrayIndexOutOfBoundsException が発生します。

つまり「負の値」または「size以上」のインデックスが原因になります。参考:Java SE API。

配列に入れられる型は固定

まず配列は宣言した型の要素しか格納できません。

例えばint[]にはint、String[]にはStringを入れます。

したがってコンパイル時の型チェックで、意図しない値の混入を防げます。

さらに参照型の配列(例:String[])には、文字列そのものではなくオブジェクトへの参照が入ります。

そのためコピーや更新の挙動に影響することがあります。

まずは「参照型配列は、要素がオブジェクトへのリンクになっている」と理解しておくと十分です。

配列の宣言・生成・初期化

まず配列を使う最初のステップは宣言です。

しかし宣言しただけでは配列本体はまだ用意されていません。

したがって「宣言 → 生成(new) → 初期化」という順番で理解すると混乱しにくいです。

配列の宣言

まず基本形は 型名[] 変数名; です。

例えば int[] scores; のように書きます。

なお int scores[] でも動きますが、一般的には int[] scores が読みやすく推奨されます。

宣言と初期化の細かいパターンを整理したい場合は、以下の内部リンクが便利です。

配列の生成と要素数の指定

次に配列は new で生成します。

例えば int[] scores = new int[5]; と書くと、intを5個入れられる配列が作られます。

さらに生成時に指定した要素数が配列の長さになり、あとから変更できません。

そのため要素を増やしたい場合は「新配列を作ってコピー」するか、可変長のArrayListを使うのが基本方針です。

なお生成直後の配列にはデフォルト値が入ります。

例えばintなら0、booleanならfalse、参照型ならnullです。

したがって未代入でも「値がない」わけではなく「初期値が入っている」点に注意してください。

配列の初期化

まず初期化には、生成してから1つずつ代入する方法と、最初から値を並べて用意する方法があります。

さらに値が固定のテストデータなら、宣言と同時に初期化すると読みやすくなります。

例えば宣言と同時に初期化するには {...} を使います。

int[] a = {1, 2, 3};
System.out.println(a.length); // 3

一方で、入力や計算結果で埋める配列は、newで作ってから代入するほうが自然です。

int[] b = new int[3];
b[0] = 10;
b[1] = 20;
b[2] = 30;

配列の要素操作とlengthの使い方

まず配列の基本操作は「代入」と「参照」です。

さらに要素数(長さ)の取得には length を使います。

したがってここを押さえるだけで、ループや境界チェックが安定します。

要素の代入と参照

まず要素へ代入するには 配列名[index] = 値; を使います。

例えば a[1] = 20; のように書きます。

次に要素を参照(取り出し)するには 配列名[index] をそのまま使います。

例えば int x = a[1]; とすると、a[1]がxに入ります。

さらに実務的には、参照と代入が混ざって「読みながら書く」処理がよく出ます。

例えば a[i] = a[i] + 1 のような形です。

そのため、同じiが“どの要素”を指すかを常に意識するとバグが減ります。

lengthで要素数を取得する

まず配列の長さは 配列変数.length で取得できます。

ただしlengthはメソッドではありません。

したがって a.length() ではなく a.length です。参考:Oracle公式チュートリアル。

さらにループで走査するときは、要素数を直書きせず i < a.length を基本にすると安全です。

そのため配列の長さが変わったときの修正が最小になり、境界ミスも減ります。

ループで配列を処理する(for / 拡張for)

まず配列の真価は繰り返し処理で発揮されます。

しかし「インデックスが必要かどうか」で書き方は変わります。

したがってfor文と拡張for文の両方を使える状態が、上達の近道です。

for文で全要素を処理する

まずfor文ではインデックスを使って走査します。

さらに「何番目かを表示する」「隣と比較する」など、位置が必要な処理に向きます。

int[] a = {10, 20, 30};

for (int i = 0; i < a.length; i++) {
  System.out.println("index=" + i + ", value=" + a[i]);
}

一方で、境界条件を i < a.length に統一しないと、例外が起きやすくなります。

したがって初心者のうちは、この条件を“型”として覚えるのが安全です。

拡張for文で全要素を処理する

次に拡張for文は for (Type v : array) の形です。

さらにインデックスが不要な集計(合計、最大値など)では短く書けます。

int[] a = {10, 20, 30};

int sum = 0;
for (int v : a) {
  sum += v;
}
System.out.println(sum);

ただし拡張for文では添字を取れません。

また基本型の場合、vを書き換えても元配列は更新されません。

そのため要素を更新したいなら、for文に戻すのが基本です。

なおfor文と拡張forの使い分けを体系的に整理したい場合は、以下の内部リンクもおすすめです。

配列の追加・削除は「新配列+コピー」で考える

まずJavaの配列はサイズ固定のため、直接の追加・削除はできません。

しかし見た目上は「新しい配列を作って中身を移す」ことで実現できます。

したがって配列で追加・削除をしたいときは、コピー手順をテンプレ化すると迷いません。

System.arraycopyで要素を追加・結合する

まず末尾に1要素追加したいなら、長さ+1の新配列を作ります。

次に元配列をコピーして、最後に追加分を入れます。

int[] a = {10, 20, 30};
int[] b = new int[a.length + 1];

System.arraycopy(a, 0, b, 0, a.length);
b[b.length - 1] = 40;

System.out.println(java.util.Arrays.toString(b));

さらに System.arraycopy(src, srcPos, dest, destPos, length) は「どこから・どこへ・どれだけ」を指定します。

したがって引数の意味をセットで覚えると、結合や部分コピーにも応用できます。参考:Java SE API(System.arraycopy)。

配列のコピーは「代入はコピーではない」を先に押さえる

まず配列変数に別の配列を代入しても、中身は複製されません。

つまり同じ配列を指す参照が共有されるだけです。

したがって片方を変更すると、もう片方にも影響します。

cloneでコピーする(基本型配列なら最短)

まず配列は clone で複製できます。

さらに基本型(intなど)の配列なら、内容も独立したコピーとして扱えます。

int[] a = {10, 20, 30};
int[] b = a.clone();

b[0] = 999;

System.out.println(java.util.Arrays.toString(a)); // [10, 20, 30]
System.out.println(java.util.Arrays.toString(b)); // [999, 20, 30]

ただし参照型配列ではシャローコピーです。

そのため要素オブジェクト自体は共有される可能性があります。

System.arraycopyでコピーする(部分コピーに強い)

一方で System.arraycopy を使う場合は、コピー先配列をnewで用意します。

さらに部分コピーができるため、区間の抜き出しや結合にも流用できます。

int[] a = {10, 20, 30, 40, 50};
int[] part = new int[3];

System.arraycopy(a, 1, part, 0, 3); // 20,30,40

System.out.println(java.util.Arrays.toString(part));

参考:Java SE API(System.arraycopy)。

配列の検索とソート

まず配列の代表的な処理として、目的の値を探す検索と、並び替えのソートがあります。

さらに「まず線形探索」「次に標準APIでソート」という順番で覚えると理解が速いです。

値を検索する(線形探索)

まず線形探索は、先頭から順に比較して一致を探します。

さらに見つからない場合に備えて、位置を-1で初期化する設計が定番です。

int[] a = {10, 20, 30, 40};
int target = 30;

int pos = -1;
for (int i = 0; i < a.length; i++) {
  if (a[i] == target) {
    pos = i;
    break;
  }
}

System.out.println(pos);

ただしStringの検索では == ではなく equals を使います。

そのため文字列の内容一致を見たいなら、array[i].equals(target) の形にしてください。

Arrays.sortでソートする(破壊的変更に注意)

次に配列のソートは java.util.Arrays.sort を使うのが基本です。

さらにこのメソッドは配列を返すのではなく、渡した配列自体の並びが変更されます。

したがって元の順序を残したい場合は、コピーしてからソートします。参考:Java SE API(Arrays)。

int[] a = {30, 10, 20};
int[] copy = a.clone();

java.util.Arrays.sort(copy);

System.out.println(java.util.Arrays.toString(a));    // [30, 10, 20]
System.out.println(java.util.Arrays.toString(copy)); // [10, 20, 30]

多次元配列(2次元配列)の基本

まず表形式データのように“行と列”で扱いたい場合は2次元配列を使います。

さらに2次元配列は「配列の配列」と考えると理解が早いです。

宣言・初期化・参照

まず int[][] table = new int[3][5]; は「長さ5のint配列が3本並ぶ」イメージです。

次に参照は table[行][列] の2つの添字で行います。

int[][] table = new int[2][3];
table[0][0] = 1;
table[0][1] = 2;
table[0][2] = 3;

table[1][0] = 4;
table[1][1] = 5;
table[1][2] = 6;

System.out.println(table[1][2]); // 6

一方で、2次元配列は行ごとに長さが違う形(ジャグ配列)も作れます。

したがって内側ループは必ず table[i].length を使います。

int[][] jag = new int[3][];
jag[0] = new int[2];
jag[1] = new int[4];
jag[2] = new int[1];

for (int i = 0; i < jag.length; i++) {
  for (int j = 0; j < jag[i].length; j++) {
    System.out.print(jag[i][j] + " ");
  }
  System.out.println();
}

よくあるエラーと対処法

まず配列のエラーは原因がパターン化しています。

しかし例外名を見て原因の見当がつくようになると、一気に楽になります。

したがって代表例だけでも「起きる条件→直し方」をセットで押さえてください。

ArrayIndexOutOfBoundsException

まず原因はインデックスが0〜length-1の範囲外になることです。

例えばループ条件を i <= array.length にしてしまうと、最後に array[array.length] に触れて例外になります。

したがって走査は i < array.length に統一してください。参考:Java SE API(AIOOBE)。

NullPointerException(参照型配列で起きやすい)

一方で参照型配列では、要素にnullが入っている可能性があります。

そのため要素をnewしていないのにメソッドを呼ぶと、NullPointerExceptionになります。

したがって「配列の生成」と「要素オブジェクトの生成」が別である点を意識してください。

String[] names = new String[2];
// names[0] は null のまま

if (names[0] != null) {
  System.out.println(names[0].length());
}

まとめ

まず配列の基本(宣言・生成・初期化・アクセス)を押さえると、Javaでのデータ処理が一段と書きやすくなります。

さらにlengthを基準に範囲を管理し、for文と拡張for文を使い分けられるようになると、配列処理が安定します。

したがって境界条件を i < array.length に統一するだけでも、例外は大きく減ります。

一方で、サイズ固定という制約があるからこそ、追加・削除は新配列+コピーで実現します。

また、代入はコピーではないため、cloneやSystem.arraycopyなど目的に合ったコピー手段を選ぶことが重要です。

その結果として、検索やソート、2次元配列も自然に扱えるようになります。

エンジニアを本気で目指すあなたへ ― 学習から実務まで一気通貫でサポート

この記事で扱ったJavaの基礎・static変数・スコープ設計は、独学ではつまずきやすい領域です。ドライブラインとZerocodeが連携し、未経験からでも実務レベルのスキル習得を徹底的にサポートします。

未経験向けキャリア育成(ドライブライン)

要件定義・設計・開発・テストまで現場準拠のカリキュラムで実務力を育成。

1on1メンター伴走支援

現役エンジニアが毎週寄り添い、課題、設計、ポートフォリオまで徹底サポート。

現役エンジニアによる技術解説(Zerocode)

Java / SQL / Spring Boot を体系的に学べる実務型オンライン講座。

完全オンラインでスキマ学習

時間や場所に縛られず、継続しやすい学習環境。

「未経験からエンジニアになりたい」「Javaを体系的に学びたい」あなたを、私たちは全力で支援します。まずはそれぞれの公式ページで詳細をご覧ください。

Join us! 未経験からエンジニアに挑戦できる環境で自分の可能性を信じてみよう 採用ページを見る→

記事監修

ドライブライン編集部

[ この記事をシェアする ]

記事一覧へ戻る