Loading
  • LIGHT

  • DARK

ROUTE

ルートゼロの
アクティビティ

Java配列とArrayListの違い徹底比較!実務で使い分ける5つの基準

3

はじめに|この記事で得られる価値

「レビューで『ここは ArrayList が良い』と言われたけれど、
なぜ 配列 ではダメなのか説明できない……。」

私たちが開発現場で何度も遭遇する、典型的なモヤモヤです。
サイズ固定・可変といった表面的な違いは知っていても、
なぜそれがパフォーマンス差につながるのかまでは曖昧になりがちです。

この記事では、その疑問をメモリ構造という視点から分解します。
「なんとなく」ではなく、技術的根拠を持って選択できる状態を目指しましょう。


結論:本質的な違いは「サイズ変更の可否」

まず結論です。
両者の最も重要な違いは、サイズを変更できるかどうかにあります。

  • 配列 (Array):作成時にサイズが決まり、その後は変更できない固定長構造
  • ArrayList:要素数に応じて内部サイズが変化する可変長構造

この差が、速度・メモリ効率・設計思想に直結します。


配列 (Array) とは何か

配列は、同一型データを連続したメモリ領域に格納する最小構成のデータ構造です。
構造が単純な分、参照処理が極めて高速という特徴があります。


int[] numbers = new int[3];
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;
  
  • メモリ配置が固定
  • インデックスアクセスは一定時間(O(1))
  • サイズ変更は不可

用語解説:配列(Array)
複数の同じ型のデータをまとめて管理できるデータ構造。Javaでは「int[]」などで宣言し、要素数は作成時に決まる。

用語解説:メモリ領域
プログラムがデータを一時的に保存する場所。配列はこの領域に連続してデータを格納する。

用語解説:O(1)
アルゴリズムの計算量を表す記号で「一定時間で処理できる」ことを意味する。


ArrayList とは何か

ArrayListは、配列を内部に持つコレクションクラスです。
サイズ管理をクラス側が肩代わりしてくれるため、私たちは要素数を意識せずに扱えます。


ArrayList<String> names = new ArrayList<>();
names.add("田中");
names.add("鈴木");
names.add("佐藤");
  
  • 内部実装は配列
  • 要素追加時に自動リサイズ
  • 操作APIが豊富

(Javaのコレクションやリスト型の違いについては『Spring Boot実践ガイド|List型・Map型の違いとBeanクラスの基礎&応用』もご参照ください)

用語解説:ArrayList
Javaのコレクションフレームワークの一つ。内部的には配列を使い、要素の追加・削除が簡単にできる可変長リスト。

用語解説:コレクション
複数のデータをまとめて扱うための仕組み。ArrayListやHashMapなどが含まれる。


5つの観点で比較:配列 vs ArrayList

観点 配列 ArrayList
サイズ 固定長 可変長
参照速度 非常に高速 高速(わずかなオーバーヘッドあり)
追加・削除 不向き 容易
扱える型 プリミティブ / オブジェクト オブジェクトのみ
機能 最小限 豊富

重要なのは「どちらが優れているか」ではなく、
用途に対してどちらが適切かです。


なぜ性能差が出るのか:メモリ構造の違い

■ 配列が高速な理由

配列は、メモリ上に連続配置されます。
そのため、要素アクセスは次の計算だけで完了します。


先頭アドレス + (index × データサイズ)
  

分岐や探索が不要なため、CPUキャッシュ効率も高くなります。

用語解説:連続配置
データがメモリ上で途切れず並んでいる状態。CPUが効率よくアクセスできる。


■ ArrayListで発生するコスト

ArrayListは容量を超えると、以下の処理が走ります。

  • より大きな配列を新規確保
  • 既存データをすべてコピー
  • 古い配列を破棄

この全件コピーが、追加処理のコスト源です。
ただし平均計算量は O(1) に近く、通常用途では問題になりません。

用語解説:全件コピー
配列のサイズを超えたとき、すべての要素を新しい配列に移し替える処理。これが追加時のコスト増加の原因。


実務向け判断フロー

  • 要素数は最初から確定しているか? → Yes:配列 / No:ArrayList
  • 頻繁な追加・削除があるか? → Yes:ArrayList
  • プリミティブ型を大量に扱い、性能最優先か? → Yes:配列 / No:ArrayList

多くの業務アプリでは、ArrayListが第一選択になります。


実務でハマりやすい3つの罠

① Arrays.asList() は可変ではない


List<String> list = Arrays.asList("a", "b", "c");
list.add("d"); // UnsupportedOperationException
  

対策:


List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
  

(Javaのエラーや例外の原因・対策については『Spring Boot NullPointerException完全対策|3大原因と実装例まとめ』もご参照ください)

用語解説:Arrays.asList()
配列をリストに変換するJavaのメソッド。ただし生成されるリストはサイズ変更不可。

用語解説:UnsupportedOperationException
実行時に許可されていない操作を行った場合に発生する例外(エラー)。


② ArrayList<int> は使えない

ジェネリクスオブジェクト型のみ対応です。

primitive wrapper
int Integer
double Double
boolean Boolean

用語解説:ジェネリクス
クラスやメソッドで扱うデータ型を、実行時ではなくコンパイル時に指定できるJavaの仕組み。ArrayList<String>など。

用語解説:プリミティブ型
intやdoubleなど、Javaの基本的なデータ型。オブジェクトではない。

用語解説:ラッパークラス
プリミティブ型をオブジェクトとして扱うためのクラス。例:int→Integer。


③ ループ中の remove() は危険

拡張for文中の削除は、ConcurrentModificationExceptionの原因になります。


numbers.removeIf(n -> n == 2);
  

用語解説:ConcurrentModificationException
コレクション(リストなど)をループ中に変更した場合に発生するエラー。安全に操作するにはIteratorを使う。

用語解説:拡張for文
Javaのfor-each構文。コレクションや配列の全要素を簡単に繰り返し処理できる。


まとめ:選択基準を言語化できるようになる

  • 配列:固定長・高速参照・低オーバーヘッド
  • ArrayList:可変長・高い柔軟性・実務向き
  • 性能差の正体はメモリ配置とコピーコスト

判断理由を説明できるようになると、
レビュー指摘は「修正」から「設計議論」に変わります。

ぜひ手元のコードで、配列とArrayListを意識的に使い分けてみてください。

RANKINGranking-icon

LATEST POSTS

もっとルートゼロを知りたいなら

DISCOVER MORE