配列は固定サイズのリスト
Javaの配列は、同じ型の値を決まった個数だけ順番に並べて保持し、位置によってアクセスします。「固定」が重要な言葉です。いったん配列を作ると、その長さは決して変わりません。そして「同じ型」: int[] は int の値だけを、String[] は文字列だけを保持します。この硬さは、配列が高速でメモリ効率がよいことの代償です。
配列の型は、要素の型のうしろに [] を付けて宣言し、そのあとリテラルを代入するか、new で確保します:
角かっこは型のうしろ(int[] scores)にも、名前のうしろ(int scores[])にも置けます。どちらもコンパイルできますが、int[] scores がJavaの慣用的なスタイルです - [] は本来あるべき場所、つまり型のそばに置きましょう。
newで配列を作る
値はまだ分からないがサイズは分かっている場合は、new を使います。これは枠を確保し、その型のデフォルト値で埋めます:
デフォルト値はランダムなゴミではありません - Javaはすべての要素をゼロで初期化します。数値型は 0(または 0.0)から始まり、boolean は false から始まり、String のような参照型は null から始まります。この null は覚えておく価値があります。確保したばかりの String[] は null だらけで、そのいずれかでメソッドを呼ぶと NullPointerException がスローされます。
インデックスはゼロから始まる
要素はインデックスで読み書きし、0 から数えます。最後の有効なインデックスは常に length - 1 です:
一部のスクリプト言語の配列とは違い、範囲外に出てもこっそり null や undefined を返したりはしません - 例外をスローします。存在しないインデックスを読んでみましょう:
このプログラムは次のようにクラッシュします:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3
これは初心者が最もよく犯すエラーの一つです。直し方はたいていループ条件のオフバイワン(1つずれ)の間違いです - < のつもりで <= を使ってしまうことです。
lengthはメソッドではなくフィールド
すべての配列は、自分のサイズを length フィールドに持っています。注意: かっこはありません。
誰もが一度はひっかかる落とし穴があります。配列は .length(フィールド)を使いますが、String は .length()(メソッド)を使います。配列に nums.length() と書くのはコンパイルエラーで、文字列に text.length と書くのも同じくエラーです。同じ単語でもルールが違います - 配列のほうにはかっこがありません。
配列をループで回す
for-eachループは前のページで学びました。インデックスが不要なときに、すべての要素を読むいちばんすっきりした方法です:
インデックスが必要なとき - 位置番号を表示する、その場で要素を書き換える、逆順にたどる - には、length を上限にした昔ながらのインデックス付き for ループを使います:
条件は i < names.length であり、<= ではありません。<= を使うと1歩行きすぎて、前の節で見た範囲外例外をスローします。簡単なルール: 値を読むだけなら for-each、位置が必要だったり配列に書き戻したりするならインデックス付き for です。
多次元配列
2次元配列は実のところ配列の配列です - 行と列のグリッドだと考えてください。角かっこをもう一組追加します:
grid[行][列] は単一のセルを選びます。各行はそれ自体が配列なので、grid.length は行数、grid[0].length は最初の行の列数です。行の長さがそろっている必要すらありません(これをジャグ配列と呼びます)が、ほとんどのグリッドは長方形です。
Arraysユーティリティクラス
配列そのものにはほとんどメソッドがありません - 直接ソートしたり、役に立つ形で表示したりはできません。Javaはまさにこのために、静的なヘルパーが詰まった java.util.Arrays ユーティリティクラスを用意しています:
ここで頼りにできる点がいくつかあります。Arrays.toString(arr) は配列を表示する正しい方法です - 直接表示すると [I@1b6d3586 のような役に立たない文字列が出てきます。Arrays.sort はその場でソートします。Arrays.copyOf は「リサイズ」のやり方です: 指定した長さの新しい配列を返し、デフォルト値で埋めます(上の例の余分な2枠は 0)。そして Arrays.binarySearch は、すでにソート済みの配列でのみ正しく動作します。
配列とArrayListの比較
サイズが最初から分かっていて変わらないとき - 曜日の固定セット、ゲーム盤、ピクセルデータ - には素の配列を使いましょう。配列は高速で軽量ですが、その固定長は実際の制約です: 長さ6の配列には、まったく新しいものを作り直さない限り7番目の要素を追加できません。
要素を自由に追加・削除する必要が出てきた瞬間、配列は扱いにくくなります。そのためにあるのが ArrayList です - コピー処理を代わりにやってくれる、サイズ変更可能で伸び縮みするリストです。
次へ: ArrayList
いくつ要素を持つことになるか分からないとき、あるいはその数がプログラムの実行中に変わるとき、固定長の配列は邪魔になります。ArrayList はJavaの答えです: インデックスのやりくりではなく add と remove のメソッドを使って、必要に応じて伸び縮みするリストです。それが次のテーマです。
よくある質問
Javaで配列を宣言して初期化するにはどうすればいいですか?
型を角かっこ付きで宣言し、リテラルを代入します: int[] nums = {1, 2, 3};。固定サイズの空の配列を作るには new を使います: int[] nums = new int[5]; - これで5つの枠が用意され、それぞれがデフォルト値で埋められます(int なら 0、オブジェクトなら null)。
Javaで配列の長さを取得するにはどうすればいいですか?
length フィールドを使います(かっこなし): nums.length。これはメソッドではなくフィールドなので、nums.length() はコンパイルエラーになります。なお、String はかっこ付きの .length() を使い、配列はかっこなしの .length を使います - よくある混同です。
Javaの配列は作成後にサイズを変更できますか?
いいえ。Javaの配列は作成時に決まった固定長を持ち、大きくも小さくもできません。サイズを変更できるリストが必要なら、代わりに ArrayList を使ってください。配列を「リサイズ」するには、より大きな新しい配列を作って要素をコピーすることになります。
JavaのArrayIndexOutOfBoundsExceptionとは何ですか?
存在しないインデックス - 0 未満、または >= array.length - にアクセスしたときに発生する実行時エラーです。一部の言語と違い、Javaは範囲外アクセスに対してデフォルト値や null を返さず、例外をスローします。有効なインデックスは常に 0 から length - 1 までです。