Javaの基礎知識(基礎編)

【Javaの基礎知識】List・Set・Mapの基本と活用法を解説!

Javaではデータを扱う方法として、配列(Array) と コレクション(List・Set・Map) の2つがあります。配列はシンプルで高速ですが、サイズ固定のため扱いにくい場面もあります。一方、コレクションは柔軟にデータを管理できるため、現在のJava開発では主流になっています。本記事では、配列の基本から List、Set、Map の使い方までを詳しく解説し、それぞれの違いと適切な選択方法についても説明します。

Javaのコレクションフレームワークとは?

Javaのコレクションフレームワークは、データを効率的に管理・操作するための仕組みです。プログラムでは、多くのデータを扱う場面があり、それを適切に整理・検索・更新するためのデータ構造が必要になります。

従来、Javaでは配列(Array)が基本的なデータ構造として使われていましたが、配列はサイズが固定されているため、可変なデータを扱うには不便でした。そこで登場したのが、 ListSetMapといったコレクションです。

コレクションとは?

Javaの「コレクション」とは、データをまとめて管理するための仕組み です。例えば、複数のデータを扱うときに、配列( Array)を使う方法がありますが、配列はサイズを変更できないという制約があります。

一方で、コレクションを使うと、データを柔軟に追加・削除 できるため、より実用的です。また、リストのように「順番を保持」したり、重複を防ぐセットのような仕組みもあります。

コレクションにはいくつかの種類があり、用途に応じて使い分けます。

  • List:順番を保持し、重複を許容** 。(例: ArrayList, LinkedList
  • Set:順番を保持せず、重複を許さない。(例: HashSet, TreeSet
  • Map:キーと値のペア でデータを管理する。(例: HashMap, TreeMap

例えば、「果物を保存する箱」を考えてみましょう。

  • List は「並べた順番を記憶できる箱」。
  • Set は「同じものを二度入れられない箱」。
  • Map は「名前とセットで保存できる箱」。

コレクションを利用することで、データを動的に追加・削除できるだけでなく、検索・ソート・重複管理などの高度な操作も可能になります。

配列(Array)の基本とコレクションとの違い

Javaでは配列( Array)とコレクション( ListSetMap)の両方が存在します。ここでは、配列の特徴と、コレクションとの違いを解説します。

Javaにおける配列の現状

Javaでは、配列(Array)は古典的なデータ構造 であり、現在では ListSetMap などのコレクションを使うのが主流 になっています。以下のような理由から、配列の使用は限定的になっています。

配列は固定長で柔軟性に欠ける

配列は、 int[]String[] のように固定長のデータ構造 であり、一度サイズを決めると変更できません。そのため、可変長のデータを扱うには不便です。

List(特に ArrayList)がほぼ配列の代替になっている

可変長のデータを扱う際、 ArrayList が配列の代替として利用されることがほとんどです。 ArrayList は、内部的に配列を使用しながらも、要素の追加・削除を柔軟に行えます。

Javaの標準APIの多くが List や Map を前提に設計されている

現在の Java の標準APIは、ほとんどが ListMap を前提に設計されています。そのため、配列よりもコレクションを使ったほうが、APIとの親和性が高く、開発効率が向上します。

低レベルな操作では配列もまだ使われる

ただし、配列はメモリ効率が良く、処理速度が速いため、パフォーマンスを求める場面では今でも利用されます。特に、大量のデータを処理する際や、低レベルなアルゴリズム実装では配列が好まれることがあります。

配列の特徴

  • 固定長(サイズを変更できない)
  • 型の制約が厳しい(宣言時に型を決める必要がある)
  • 高速なインデックスアクセスが可能

配列の使い方

配列の宣言と初期化

int[] numbers = {1, 2, 3, 4, 5};
String[] names = new String[3];

要素の取得と変更

int firstNumber = numbers[0]; // 1
names[0] = "Alice";

配列の反復処理(for / foreach)

for (int i = 0; i < numbers.length; i++) {
    System.out.println(numbers[i]);
}

for (int num : numbers) {
    System.out.println(num);
}

配列とコレクション(List)の違い

特徴配列(Array)List
サイズ変更不可(固定長)可能(動的に追加・削除)
データ構造プリミティブ型とオブジェクト型オブジェクト型のみ
操作の柔軟性低レベルの操作(要素の直接操作)便利なメソッドが豊富( add()remove() など)

Arrays.asList() で配列を List に変換

List<String> list = Arrays.asList(names);
System.out.println(list.get(0)); // Alice

Listの基本と使い方

リスト( List)は、要素の順序を保持し、重複を許容するデータ構造です。配列とは異なり、可変長のデータを扱うことができ、要素の追加や削除が容易です。また、 ArrayListLinkedList のような異なる実装が存在し、それぞれ特徴があります。本記事では、 List の基本的な特徴、主な実装クラス、操作方法について詳しく解説します。

Listの特徴

List は、Javaのコレクションフレームワークの中で最も基本的なデータ構造の一つであり、要素の順序を保持し、重複を許容する という特徴を持っています。配列と異なり、動的にサイズを変更できるため、データの追加・削除が柔軟に行えます。

ArrayListLinkedList などの異なる実装クラスがあり、それぞれの特性に応じて適切な選択が求められます。ここでは、 List の主な特徴について解説します。

Listの特徴

  • 順序を保持する(要素を追加した順番を維持)
  • 重複を許容する(同じ値を複数回格納可能)
  • インデックスでアクセス可能(get(index) で取得)

Listの主な実装クラス

Javaの Listインターフェースを実装する主なクラスである ArrayListLinkedListVector を比較した表です。

特徴ArrayListLinkedListVector
データ構造可変長配列双方向リンクリスト可変長配列
要素の追加末尾への追加は高速先頭・途中の追加が高速同期処理のため若干遅い
要素の削除途中の削除は低速途中の削除が高速同期処理のため若干遅い
検索・アクセスインデックスによる高速アクセス線形検索が必要で遅いインデックスによる高速アクセス
スレッドセーフ非同期(スレッドセーフでない)非同期(スレッドセーフでない)同期処理されておりスレッドセーフ
推奨用途データ量が多く、検索やランダムアクセスが多い場合要素の追加・削除が頻繁に発生する場合古いコードでスレッドセーフなリストが必要な場合(非推奨)

ArrayList

ArrayList は、内部的に可変長配列を使用しており、ランダムアクセスが高速です。要素の追加・取得が速い反面、途中の要素を削除するとシフト処理が発生し、パフォーマンスに影響を与えることがあります。

List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
System.out.println(list.get(0)); // Java

LinkedList

LinkedList は、要素がノードとしてリンクリストで管理されており、要素の追加・削除が高速です。一方で、ランダムアクセスの速度は ArrayList に比べて遅くなります。

List<String> linkedList = new LinkedList<>();
linkedList.add("C++");
linkedList.add("Ruby");
System.out.println(linkedList.get(1)); // Ruby

Vector(推奨されない)

VectorArrayList と似ていますが、スレッドセーフであるため、並行処理の環境で利用されることがあります。しかし、現在では ArrayList を使い、必要なら Collections.synchronizedList() を使用する方法が推奨されています。

List<String> vector = new Vector<>();
vector.add("Go");
vector.add("Swift");
System.out.println(vector.get(0)); // Go

Listの操作方法

List は、要素の追加・削除、取得、ループ処理などの操作が簡単に行えるデータ構造です。 ArrayListLinkedList を使用することで、データの管理や検索を効率的に行うことができます。

ここでは、 List における基本的な操作方法として、「要素の追加・削除」「要素の取得」「イテレーション(反復処理)」の使い方を紹介します。

要素の追加・削除

List は、 add() メソッドを使って要素を追加し、 remove() メソッドで要素を削除できます。

List<String> list = new ArrayList<>();
list.add("JavaScript");
list.remove("JavaScript");

要素の取得

get(index) を使用すると、指定した位置の要素を取得できます。

String element = list.get(0);
System.out.println(element);

イテレーション(反復処理)

リストの要素を順番に処理する方法として、拡張 for 文や Iterator を使用する方法があります。

for (String item : list) {
    System.out.println(item);
}

Iterator<String> iterator = list.iterator();

while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

Setの基本と使い方

セット( Set)は、重複を許さないデータ構造です。リスト( List)とは異なり、同じ要素を複数回追加することができません。また、実装クラスによって、要素の順序やソートの有無が異なります。本記事では、 Set の基本的な特徴、主な実装クラス、操作方法について詳しく解説します。

Setの特徴

Set は、重複を許さないデータ構造 であり、同じ要素を複数回追加することができません。そのため、ユニークなデータの管理 に適しています。

また、 Set の実装クラスによって、要素の順序やソートのルールが異なります。順序を保持しない HashSet、挿入順を維持する LinkedHashSet、自動ソートされる TreeSet など、用途に応じて適切な Set を選択することが重要です。

Setの特徴

  • 順序を保証しない(ただし、TreeSet は要素を自動的にソートする)
  • 重複を許さない(同じ要素が2回以上追加されることはない)
  • equals() と hashCode() の適切な実装が重要

Setの主な実装クラス

Javaの Setインターフェースを実装する代表的なクラスである HashSetLinkedHashSetTreeSet の特徴を比較します。

特徴HashSetLinkedHashSetTreeSet
データ構造ハッシュテーブルハッシュテーブル + リンクリスト赤黒木(バランスツリー)
要素の順序順序なし挿入順を維持昇順にソート
重複の可否重複不可重複不可重複不可
要素の追加・削除高速(O(1))やや低速(O(1) + 挿入順管理)遅い(O(log n))
検索の速度高速(O(1))高速(O(1))やや遅い(O(log n))
並び順の保証保証しない挿入順を保証ソート順を保証
主な用途順序を気にせず、高速にデータを管理したい場合要素の順番を保持しつつ、重複を防ぎたい場合データを常にソートして管理したい場合

HashSet

HashSet は、ハッシュテーブルを使用して要素を格納するため、順序を保持しない 代わりに、高速な追加・削除・検索 を提供します。

Set<String> hashSet = new HashSet<>();
hashSet.add("Java");
hashSet.add("Python");
System.out.println(hashSet.contains("Java")); // true

LinkedHashSet

LinkedHashSet は、 HashSet の特性を持ちつつ、要素の挿入順を保持 します。そのため、データの順番を維持しながら、効率的に重複を防ぎたい場合に適しています。

Set<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("C++");
linkedHashSet.add("Ruby");
System.out.println(linkedHashSet); // [C++, Ruby]

TreeSet

TreeSet は、要素を自動的にソート するセットです。内部的には TreeMap を使用しており、追加・削除のコストは高めですが、常に昇順でデータを保持します。

Set<Integer> treeSet = new TreeSet<>();
treeSet.add(5);
treeSet.add(1);
treeSet.add(3);
System.out.println(treeSet); // [1, 3, 5](自動的にソートされる)

Setの操作方法

Set は、重複を許さず、要素の順序が保証されない(またはソートされる)データ構造です。基本的な操作として、「要素の追加・削除」「特定の要素が含まれているかのチェック」「セットの全要素を取得する反復処理(イテレーション)」が可能です。

List のようなインデックスアクセスはできませんが、その分、データの一意性を確保しながら効率的に管理 できる利点があります。ここでは、 Set の基本操作を詳しく解説します。

要素の追加・削除

Set では、 add() を使用して要素を追加し、 remove() で要素を削除できます。

Set<String> set = new HashSet<>();
set.add("JavaScript");
set.remove("JavaScript");

含まれているかのチェック

特定の要素がセット内に存在するかを確認するには、 contains() を使用します。

boolean exists = set.contains("Python");
System.out.println(exists); // true または false

反復処理(イテレーション)

Set は、 for-each 文や Iterator を使って反復処理が可能です。

for (String item : set) {
    System.out.println(item);
}

Iterator<String> iterator = set.iterator();

while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

Mapの基本と使い方

マップ( Map)は、**キーと値のペアでデータを管理** するデータ構造です。リスト( List)やセット( Set)とは異なり、特定のキーを使って値にアクセスできるため、効率的なデータ管理が可能です。

用途に応じて適切な Map を選択することが重要です。本記事では、 Map の基本的な特徴、主な実装クラス、操作方法について解説します。

Mapの特徴

Map は、**キーと値のペアでデータを管理するデータ構造** です。各キーは一意であり、同じキーに対して異なる値を設定すると、後から追加した値で上書きされます。

配列やリストとは異なり、 Map はデータをキーで管理できるため、**特定の要素を高速に検索** するのに適しています。また、実装クラスによって、キーの順序やソートのルールが異なるため、用途に応じた適切な選択が重要です。

Mapの特徴

キーと値のペアを保持(キーを指定して値を取得できる)
キーの重複を許さない(同じキーは1つしか保持できない)
高速な検索が可能(適切な実装クラスを選べばパフォーマンスが向上)

Mapの主な実装クラス

Javaの Mapインターフェースを実装する代表的なクラスである HashMapLinkedHashMapTreeMap の特徴を比較します。

特徴HashMapLinkedHashMapTreeMap
データ構造ハッシュテーブルハッシュテーブル + 連結リスト赤黒木(バランスツリー)
キーの順序順序なし挿入順を維持キーの昇順でソート
重複の可否キーは重複不可、値は重複可能キーは重複不可、値は重複可能キーは重複不可、値は重複可能
要素の追加・削除高速(O(1))やや低速(O(1) + 順序管理)遅い(O(log n))
検索の速度高速(O(1))高速(O(1))やや遅い(O(log n))
並び順の保証保証しない挿入順を保証キーの昇順を保証
主な用途順序を気にせず、高速にデータを管理したい場合要素の順番を保持しつつ、高速な検索をしたい場合データを常にソートした状態で管理したい場合

HashMap

HashMap は、キーの順序を保持しない代わりに、高速な検索・追加・削除 を提供します。最も一般的に使用される Map の実装です。

Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("Java", 1);
hashMap.put("Python", 2);
System.out.println(hashMap.get("Java")); // 1

LinkedHashMap

LinkedHashMap は、 HashMap の特性を持ちつつ、キーの挿入順を保持 します。データの順序を維持しながら、高速な検索を行いたい場合に適しています。

Map<String, Integer> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("C++", 3);
linkedHashMap.put("Ruby", 4);
System.out.println(linkedHashMap); // {C++=3, Ruby=4}

TreeMap

TreeMap は、キーを昇順にソート して保持する Map です。内部的に Red-Black Tree(赤黒木) を使用しており、検索や順序付きのデータ管理に適しています。

Map<Integer, String> treeMap = new TreeMap<>();
treeMap.put(5, "Five");
treeMap.put(1, "One");
treeMap.put(3, "Three");
System.out.println(treeMap); // {1=One, 3=Three, 5=Five}

Mapの操作方法

Map は、キーと値のペアでデータを管理し、特定のキーを使って高速にデータを取得できます。基本的な操作として、「要素の追加・取得・削除」「キーの検索」「全要素の反復処理」があります。

配列やリストと異なり、 Map ではインデックスによるアクセスはできませんが、その分、**キーを使って効率的にデータを管理** できます。ここでは、 Map の基本的な操作方法を解説します。

要素の追加・取得・削除

Map は、 put() を使って要素を追加し、 get() で値を取得し、 remove() で削除できます。

Map<String, Integer> map = new HashMap<>();
map.put("JavaScript", 10);
map.remove("JavaScript");

キーの検索

特定のキーが Map に含まれているかを確認するには、 containsKey() を使用します。

boolean exists = map.containsKey("Python");
System.out.println(exists); // true または false

反復処理(forEach / entrySet)

Map の全要素を処理するには、 forEachentrySet() を使用できます。

map.forEach((key, value) -> {
    System.out.println(key + ": " + value);
});

for (Map.Entry<String, Integer> entry : map.entrySet()) {
    System.out.println(entry.getKey() + ": " + entry.getValue());
}

List・Set・Mapの違いを比較

ListSetMap は、それぞれ異なる特性を持つデータ構造です。適切なデータ構造を選択することで、プログラムのパフォーマンスや可読性を向上させることができます。

以下の表で、それぞれの特徴を比較し、用途に応じた選び方を解説します。

特徴ListSetMap
順序を保持×( TreeSetはソート順)×( LinkedHashMapは挿入順)
重複を許容×キーは×、値は〇
要素のアクセス方法インデックスイテレーションキーを指定

適切なデータ構造の選び方

用途に応じて、以下のように ListSetMap を使い分けると効果的です。

  • 順序を保持し、重複を許容するデータを扱いたい場合List
  • 重複を許さず、順序を気にしないデータを管理したい場合Set
  • キーと値のペアでデータを管理し、高速な検索をしたい場合Map

例えば、以下のようなケースで適切なデータ構造を選ぶことができます。

  • 同じ値を複数回扱い、要素の順序を保持したい → ArrayListList
  • 重複のないユニークな値の集合を管理したい → HashSetSet
  • 特定のキーを使って素早く値を検索したい → HashMapMap

データの管理方法に応じて、適切なデータ構造を選択することが重要です。 List は順序付きのデータ、 Set はユニークな要素、 Map はキーと値のペアを管理するのに適しています。

よくある質問(FAQ)

Q: ArrayListとLinkedListはどちらを使うべき?

A: 読み取りが多いなら ArrayList、挿入・削除が多いなら LinkedList を選ぶのが適切です。

  • ArrayList は、ランダムアクセスが高速であり、データの検索や取得を頻繁に行う場合に適しています。
  • LinkedList は、要素の追加・削除が頻繁に発生する場合に有利ですが、ランダムアクセスは遅くなります。

Q: HashSetに要素を追加すると順序が変わるのはなぜ?

A: HashSet は、**ハッシュ値を基に要素を格納** するため、順序が保証されません。

内部的にハッシュテーブルを使用しているため、要素の順番はデータのハッシュ値によって決まり、挿入した順番通りにはなりません。

もし順序を維持したい場合は、代わりに LinkedHashSet を使用すると、挿入順が保持されます。

Q: HashMapのキーはどのように管理される?

A: HashMap は、 hashCode() を利用してキーの位置を決定し、同じハッシュ値の場合は equals() で比較して管理します。

  • キーの hashCode() メソッドを利用し、ハッシュテーブルのどこに格納するかを決定します。
  • 同じハッシュ値のキーが複数存在する可能性があるため、**ハッシュの衝突(コリジョン)** を防ぐために equals() でキーの内容を比較します。
  • 衝突が発生した場合、内部的にリストやツリー構造を使って管理し、パフォーマンスを維持します。

まとめ

Javaの ListSetMap は、それぞれ異なる特性を持つデータ構造です。用途に応じて適切なデータ構造を選択することで、プログラムのパフォーマンスを向上させることができます。

データ構造ごとの特徴

Javaの ListSetMap は、それぞれ異なる特性を持つデータ構造です。適切なデータ構造を選択することで、プログラムの可読性やパフォーマンスを向上させることができます。

以下の表では、それぞれのデータ構造の主な用途と特徴を整理し、どのような場面で使うべきかを分かりやすく比較しています。

データ構造主な用途特徴
List順序を保持し、重複を許容したデータ管理インデックスでアクセス可能 / ランダムアクセスが速い
Set重複を防ぎながらデータを管理順序なし(TreeSetはソート)/ 高速な検索が可能
Mapキーと値のペアでデータを管理キーを使った高速なデータ検索が可能

適切なデータ構造の選び方

  • 順序を保持し、重複を許容したい場合List(例: ArrayList
  • 重複を許さず、一意のデータを管理したい場合Set(例: HashSet
  • キーと値のペアでデータを管理したい場合Map(例: HashMap

今後の活用

適切なデータ構造を選択することは、効率的なプログラム設計の第一歩です。各データ構造の特性をしっかり理解し、状況に応じた適切な使い分けを実践しましょう。

よく読まれている記事

1

IT入門シリーズ 🟢 STEP 1: ITの基礎を知る(ITとは何か?) 📌 IT初心者が最初に学ぶべき基本知識。ITの概念、ネットワーク、OS、クラウドの仕組みを学ぶ ...

2

「私たちが日々利用しているスマートフォンやインターネット、そしてスーパーコンピュータやクラウドサービス――これらの多くがLinuxの力で動いていることをご存じですか?無料で使えるだけでなく、高い柔軟性 ...

3

この記事は、Linuxについて勉強している初心者の方向けに「Shellスクリプト」について解説します。最後まで読んで頂けましたら、Shellスクリプトはどのような役割を担っているのか?を理解出来るよう ...

-Javaの基礎知識(基礎編)