Javaの**コレクションフレームワーク(Collection Framework)**は、データを効率的に管理・操作するための強力なツール群を提供します。コレクションフレームワークは、複数のデータを扱うためのインターフェースやクラスが体系的に整理されており、リスト、セット、マップなど、さまざまなデータ構造を効率よく利用できます。
この章では、コレクションフレームワークの基本概念から、リストやセット、マップなどの主要なデータ構造の使い方、そしてジェネリクスやストリームAPIを活用した高度な操作方法について解説します。具体的には、以下の内容をカバーします:
- コレクションフレームワークの基本
- リスト(List)インターフェース
- セット(Set)インターフェース
- マップ(Map)インターフェース
- ジェネリクスを使ったコレクションの型安全性
- ストリームAPIによるコレクション操作
12.1 コレクションフレームワークとは?
コレクションフレームワークは、Javaで複数のデータを管理・操作するためのインターフェースやクラスを提供する仕組みです。リストやセット、マップといったデータ構造を使い、配列よりも柔軟で効率的にデータの操作を行うことができます。
コレクションフレームワークは、以下の3つの主要なインターフェースで構成されています:
- List: 順序を保持し、要素の重複を許容するコレクション。
- Set: 順序を保持せず、要素の重複を許容しないコレクション。
- Map: キーと値のペアで要素を保持し、キーの重複を許容しないコレクション。
12.1.1 コレクションフレームワークのメリット
コレクションフレームワークを使うことで、以下のようなメリットがあります:
- データ構造の一貫性: 共通のインターフェースを使用することで、操作が一貫して行えます。
- 効率的なメモリ管理: 必要に応じてサイズが変更でき、メモリの無駄を最小限に抑えられます。
- 豊富な機能: ソートや検索、データの変換など、便利な機能が標準で提供されています。
12.2 Listインターフェース 〜順序を持つデータ構造〜
Listは、順序を持ち、同じ要素を複数回保持できるデータ構造です。リストは、インデックスを使って要素にアクセスできるため、配列に似た構造を持っていますが、配列とは異なり、リストはサイズを動的に変更できます。
12.2.1 ArrayListの使い方
ArrayList
は、List
インターフェースを実装した最も一般的なクラスで、可変長の配列として動作します。以下は、ArrayList
の基本的な操作です。
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
// ArrayListの作成
ArrayList<String> fruits = new ArrayList<>();
// 要素の追加
fruits.add("リンゴ");
fruits.add("バナナ");
fruits.add("オレンジ");
// 要素の取得
System.out.println(fruits.get(1)); // インデックス1の要素を取得
// リストの全要素をループ
for (String fruit : fruits) {
System.out.println(fruit);
}
// 要素の削除
fruits.remove("バナナ");
System.out.println(fruits);
}
}
12.2.2 LinkedListの使い方
LinkedList
は、List
インターフェースを実装したもう一つのクラスで、双方向の連結リストとして動作します。ArrayList
はランダムアクセスに優れていますが、LinkedList
は要素の追加や削除が効率的に行えます。
import java.util.LinkedList;
public class Main {
public static void main(String[] args) {
// LinkedListの作成
LinkedList<String> queue = new LinkedList<>();
// 要素の追加
queue.add("ジョン");
queue.add("ポール");
queue.add("ジョージ");
// 先頭の要素を取得(削除せず)
System.out.println(queue.peek());
// 先頭の要素を取得し、リストから削除
System.out.println(queue.poll());
// 残りの要素を表示
System.out.println(queue);
}
}
LinkedList
はキューやスタックとしても使用でき、先入れ先出し(FIFO)や後入れ先出し(LIFO)のデータ操作が簡単に実現できます。
12.3 Setインターフェース 〜重複を許さないコレクション〜
Setは、重複する要素を持たないコレクションです。セットは順序を持たないため、追加した順序を保証しませんが、データの一意性を保つ場面で役立ちます。代表的なセット実装には、HashSet
とTreeSet
があります。
12.3.1 HashSetの使い方
HashSet
は、要素をハッシュテーブルを使って管理し、重複する要素を許しません。また、順序も保持しません。
import java.util.HashSet;
public class Main {
public static void main(String[] args) {
// HashSetの作成
HashSet<String> cities = new HashSet<>();
// 要素の追加
cities.add("東京");
cities.add("大阪");
cities.add("名古屋");
cities.add("東京"); // 重複した要素は追加されない
// Setの全要素をループ
for (String city : cities) {
System.out.println(city);
}
// 要素の存在チェック
if (cities.contains("大阪")) {
System.out.println("大阪がセットに含まれています。");
}
}
}
12.3.2 TreeSetの使い方
TreeSet
は、要素を自然順序に基づいてソートし、重複を許さないセットです。ソートされた順序で要素が保持されるため、数値やアルファベット順にデータを管理したい場合に便利です。
import java.util.TreeSet;
public class Main {
public static void main(String[] args) {
// TreeSetの作成
TreeSet<Integer> numbers = new TreeSet<>();
// 要素の追加
numbers.add(5);
numbers.add(1);
numbers.add(10);
numbers.add(3);
// 自然順序でソートされた要素を表示
for (int num : numbers) {
System.out.println(num);
}
}
}
TreeSet
はSortedSet
インターフェースを実装しているため、要素が常にソートされた状態で保持されます。
12.4 Mapインターフェース 〜キーと値のペアでデータを管理する〜
Mapは、キーと値のペアでデータを管理するコレクションです。キーは一意でなければならず、同じキーに対して複数の値を設定することはできません。Map
は、検索やデータの関連付けに非常に便利です。
12.4.1 HashMapの使い方
HashMap
は、キーと値のペアをハッシュテーブルで管理する一般的なマップです。キーの順序は保持されませんが、要素の追加・削除・検索が高速に行えます。
import java.util.HashMap;
public class Main {
public static void main(String[] args) {
// HashMapの作成
HashMap<String, Integer> ages = new HashMap<>();
// 要素の追加
ages.put("太郎", 25);
ages.put("花子", 30);
ages.put("次郎", 22);
// 特定のキーに対応する値を取得
System.out.println("太郎の年齢: " + ages.get("太郎"));
// Mapの全要素をループ
for (String name : ages.keySet()) {
System.out.println(name + "の年齢は " + ages.get(name) + " 歳です。");
}
}
}
12.4.2 TreeMapの使い方
TreeMap
は、キーに基づいてデータをソートして保持するマップです。キーが自然順序に従ってソートされるため、ソートされた順序でデータを管理したい場合に役立ちます。
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
// TreeMapの作成
TreeMap<String, Integer> scores = new TreeMap<>();
// 要素の追加
scores.put("Alice", 85);
scores.put("Bob", 92);
scores.put("Charlie", 78);
// 自然順序でソートされたMapの要素を表示
for (String name : scores.keySet()) {
System.out.println(name + "のスコアは " + scores.get(name) + " 点です。");
}
}
}
12.5 ジェネリクス 〜型安全なコレクションの実現〜
Javaのコレクションフレームワークでは、デフォルトでジェネリクスが使用されます。**ジェネリクス(Generics)**を使うことで、コレクションに格納できる要素の型を指定し、型安全性を高めることができます。ジェネリクスを使うことで、コンパイル時に型の不一致を防ぐことができます。
12.5.1 ジェネリクスの基本構文
コレクションにジェネリクスを適用する例を以下に示します。ArrayList
にString
型の要素だけを格納する場合、ジェネリクスを使って型を明示的に指定します。
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
// ジェネリクスを使ってString型のリストを作成
ArrayList<String> names = new ArrayList<>();
// String型の要素を追加
names.add("太郎");
names.add("花子");
// コンパイルエラー:整数は追加できない
// names.add(123);
// リストの全要素を表示
for (String name : names) {
System.out.println(name);
}
}
}
ジェネリクスを使うことで、リストに格納するデータ型を強制し、意図しない型のデータが追加されることを防げます。
12.6 Stream API 〜コレクションの高度な操作〜
Java 8で導入されたStream APIは、コレクションの操作を簡潔かつ効率的に行うための強力なツールです。ストリームは、データの集まりを処理するための抽象化された操作のシーケンスを提供し、フィルタリング、ソート、マッピング、集計などの操作が簡単に行えます。
12.6.1 Streamの基本操作
Stream
を使ってコレクションをフィルタリングし、操作する例を示します。
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<String> names = new ArrayList<>();
names.add("太郎");
names.add("花子");
names.add("次郎");
names.add("二郎");
// "郎"で終わる名前をフィルタリング
List<String> filteredNames = names.stream()
.filter(name -> name.endsWith("郎"))
.collect(Collectors.toList());
// フィルタリングされた名前を表示
filteredNames.forEach(System.out::println);
}
}
12.6.2 ソートや集計操作
Stream
を使えば、簡単にソートや集計などの操作も行えます。
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(5, 2, 9, 3, 7);
// ソート
numbers.stream()
.sorted()
.forEach(System.out::println);
// 合計を計算
int sum = numbers.stream().mapToInt(Integer::intValue).sum();
System.out.println("合計: " + sum);
}
}
12.7 Javaのコレクションフレームワークまとめ
この章では、Javaのコレクションフレームワークについて学びました。コレクションフレームワークは、効率的にデータを管理・操作するための重要なツールであり、List
、Set
、Map
など、さまざまなデータ構造を提供しています。また、ジェネリクスを使って型安全なコレクションを実現し、Stream API
を使うことで、コレクションのデータを高度に処理することが可能です。