Java:List と Map
1学習の目的
- 要素を後から追加・削除できる List を使えるようになる。長さを先に決める必要がなくなり、配列の制約から解放される。
- キーで値を取り出す Map を使えるようになる。「商品名から在庫を引く」といった検索が、ループなしで一発でできるようになる。
2基礎解説
配列は長さを先に決める必要があり、後から変えられません。実際のデータは何件になるか分からないことが多く、そこで使うのが List です。
| 配列 | List | Map | |
|---|---|---|---|
| 長さ | 固定 | 自由に増減 | 自由に増減 |
| 取り出し | a[0] | list.get(0) | map.get("キー") |
| 件数 | a.length | list.size() | map.size() |
| 向いている | 件数が決まっている | 順番に並べる | キーで検索 |
- List<String> list = new ArrayList<>(); が基本形。<> の中に入れる型を書く。左辺は List、右辺は ArrayList と書くのが慣習。
- 基本型はそのまま入れられない。List<int> ではなく List<Integer> と書く。int → Integer、double → Double のようにラッパークラスを使う。
- ⚠ map.get() は見つからないと null を返す。そのまま計算に使うとエラーになるので、getOrDefault() で既定値を指定するのが安全。
- List.of() で作ったリストは変更できない。add しようとすると例外が出る。変更したいなら new ArrayList<>(List.of(…)) と包む。
- HashMap は順序が保証されない。並び順が必要なら TreeMap(キー順)や LinkedHashMap(挿入順)を使う。
現場使用例:検索結果の一覧(List)、商品コードから商品を引く(Map)、集計処理、設定値の管理。実務のJavaでは配列よりList・Mapのほうが圧倒的に多く使われる。
import java.util.*; // List, Map などをまとめて読み込む
// ① List(順番に並べる)
List<String> items = new ArrayList<>();
items.add("ノートPC");
items.add("マウス");
items.get(0); // "ノートPC"
items.size(); // 2
items.remove(0); // 0番目を削除
items.contains("マウス"); // true
items.indexOf("マウス"); // 0(無ければ -1)
for (String item : items) { … }
// 基本型は ラッパークラス で
List<Integer> nums = new ArrayList<>(List.of(30, 10, 20));
Collections.sort(nums); // [10, 20, 30]
Collections.reverse(nums); // [30, 20, 10]
Collections.max(nums); // 30
// ⚠ List.of は変更できない
List<String> fixed = List.of("A", "B");
// fixed.add("C"); → 例外が出る
// ② Map(キーと値のペア)
Map<String, Integer> stock = new HashMap<>();
stock.put("ノートPC", 5);
stock.put("マウス", 42);
stock.get("マウス"); // 42
stock.get("存在しない"); // null ⚠
stock.getOrDefault("存在しない", 0); // 0 ← 安全
stock.containsKey("ノートPC"); // true
// Map のループ
for (Map.Entry<String, Integer> e : stock.entrySet()) {
System.out.println(e.getKey() + "=" + e.getValue());
}
// ⭐ 集計の定番パターン
Map<String, Integer> count = new TreeMap<>();
for (String d : data) {
count.put(d, count.getOrDefault(d, 0) + 1);
}
3基本ドリル(10問)
出力2行。3 / ノートPC
List
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> items = new ArrayList<>();
items.add("ノートPC");
items.add("マウス");
items.add("キーボード");
System.out.println(items.size());
System.out.println(items.get(0));
}
}長さを先に決めなくてよいのがListの利点。何件になるか分からないデータを扱うときに必須になる。
A. List<int> B. List<Integer> C. List<number> D. List<Int> 選択★☆☆無料
解答 == B
基本型ではなくラッパークラスを使う。
B
List には基本型を直接入れられない。int → Integer、double → Double、boolean → Boolean と対応するクラスを使う。
出力 == 42
Map
import java.util.*;
public class Main {
public static void main(String[] args) {
Map<String, Integer> stock = new HashMap<>();
stock.put("ノートPC", 5);
stock.put("マウス", 42);
System.out.println(stock.get("マウス"));
}
}Map はキーで一発検索できる。Listなら全件ループして探すところを、1行で取り出せる。
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.____("テスト");
System.out.println(list.get(0));
}
}出力 == テスト
「加える」を意味する3文字のメソッド。
add
add で末尾に追加される。位置を指定したいなら add(0, "値") のように添字を渡す。
A. 0 B. null C. 空文字 D. エラー 選択★☆☆無料
解答 == B
見つからないときの戻り値。
B
null が返るので、そのまま計算に使うとエラーになる。getOrDefault で既定値を指定するのが安全。
出力 == 0
map.getOrDefault("キー", 0) と書く。
import java.util.*;
public class Main {
public static void main(String[] args) {
Map<String, Integer> stock = new HashMap<>();
stock.put("ノートPC", 5);
System.out.println(stock.getOrDefault("存在しない商品", 0));
}
}null チェックが不要になる。「無ければ0」という前提が明確なら、この書き方のほうが短く安全。
import java.util.*;
public class Main {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<>(List.of(30, 10, 20));
Collections.____(nums);
System.out.println(nums);
}
}出力 == [10, 20, 30]
「並べ替える」を意味する4文字のメソッド。
sort
Collections.sort は元のリストを並べ替える。配列の Arrays.sort と対になる存在。
A. 追加される B. 例外が出る C. 無視される D. コンパイルエラー 選択★★☆広告解放
解答 == B
List.of は変更できないリストを作る。
B
UnsupportedOperationException が出る。変更したいなら new ArrayList<>(List.of(…)) と包む必要がある。
出力2行。ノートPC=5 / マウス=42
for (Map.Entry
import java.util.*;
public class Main {
public static void main(String[] args) {
Map<String, Integer> stock = new TreeMap<>();
stock.put("マウス", 42);
stock.put("ノートPC", 5);
for (Map.Entry<String, Integer> e : stock.entrySet()) {
System.out.println(e.getKey() + "=" + e.getValue());
}
}
}TreeMap はキー順に並ぶ。HashMap では順序が保証されないので、出力順が実行ごとに変わる可能性がある。
出力 == [ノートPC, キーボード]
remove(1) で添字1の要素を削除する。
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> items = new ArrayList<>(
List.of("ノートPC", "マウス", "キーボード"));
items.remove(1);
System.out.println(items);
}
}削除すると後ろの要素が詰まる。配列なら固定長なので、こうした操作は自分で書く必要があった。
4実践シナリオ(5問)
出力 == [マウス, モニター]
ループしながら条件判定し、別のリストに add する。
import java.util.*;
public class Main {
public static void main(String[] args) {
List<String> items = new ArrayList<>();
items.add("ノートPC");
items.add("マウス");
items.add("モニター");
List<String> shortNames = new ArrayList<>();
for (String item : items) {
if (item.length() <= 4) {
shortNames.add(item);
}
}
System.out.println(shortNames);
}
}マウス(3文字)とモニター(4文字)が該当し、ノートPC(5文字)は除外される。何件該当するか分からなくてもListなら書ける——配列では「最大何件か」を先に決める必要があった。
出力 == {A=3, B=1, C=1}
map.put(key, map.getOrDefault(key, 0) + 1) が集計の定番。
import java.util.*;
public class Main {
public static void main(String[] args) {
String[] data = {"A", "B", "A", "C", "A"};
Map<String, Integer> count = new TreeMap<>();
for (String d : data) {
count.put(d, count.getOrDefault(d, 0) + 1);
}
System.out.println(count);
}
}この1行が集計の定番パターン。初回は getOrDefault が0を返し、2回目以降は既存の値に足される。
出力2行。5 / 0
getOrDefault を使えば null チェックが不要。
import java.util.*;
public class Main {
public static void main(String[] args) {
Map<String, Integer> stock = new HashMap<>();
stock.put("ノートPC", 5);
stock.put("マウス", 42);
System.out.println(stock.getOrDefault("ノートPC", 0));
System.out.println(stock.getOrDefault("キーボード", 0));
}
}Mapなら全件ループせずに検索できる。データが1万件あっても、取り出す速度はほとんど変わらない。
出力 == 927400
List
import java.util.*;
public class Main {
static class Product {
String name;
int price;
int stock;
Product(String name, int price, int stock) {
this.name = name;
this.price = price;
this.stock = stock;
}
int stockValue() {
return price * stock;
}
}
public static void main(String[] args) {
List<Product> items = new ArrayList<>();
items.add(new Product("ノートPC", 128000, 5));
items.add(new Product("マウス", 3200, 42));
items.add(new Product("キーボード", 8500, 18));
int total = 0;
for (Product p : items) {
total += p.stockValue();
}
System.out.println(total);
}
}ListにはどんなクラスでもDefault入れられる。自分で作ったクラスも、標準のクラスと同じように扱える。
出力 == {PC=2, 周辺機器=1}
値をキーにして数える。TreeMap で順序を固定する。
import java.util.*;
public class Main {
public static void main(String[] args) {
Map<String, String> category = new LinkedHashMap<>();
category.put("ノートPC", "PC");
category.put("デスクトップ", "PC");
category.put("マウス", "周辺機器");
Map<String, Integer> count = new TreeMap<>();
for (String c : category.values()) {
count.put(c, count.getOrDefault(c, 0) + 1);
}
System.out.println(count);
}
}values() で値だけを取り出せる。キーが必要なら keySet()、両方なら entrySet() を使い分ける。
5仕上げ課題
Product クラス:name・category・price(getterまたは直接アクセス可)
データ(List<Product> に格納)
・ノートPC / PC / 128000
・デスクトップ / PC / 98000
・マウス / 周辺機器 / 3200
・キーボード / 周辺機器 / 8500
・モニター / 周辺機器 / 45000
処理
① 全商品を「1. ノートPC(PC):128,000円」の形式で出力
② カテゴリ別の合計金額を Map で集計し、キー順に「PC:226,000円」の形式で出力
③ カテゴリ別の件数も同時に集計し、「PC:2件」の形式で出力
④ 全体の合計金額を出力
期待される出力(10行)
1. ノートPC(PC):128,000円
2. デスクトップ(PC):98,000円
3. マウス(周辺機器):3,200円
4. キーボード(周辺機器):8,500円
5. モニター(周辺機器):45,000円
---
PC:226,000円(2件)
周辺機器:56,700円(3件)
---
合計:282,700円 総合★★★広告解放
出力10行が完全一致
カテゴリ別の集計には Map
import java.util.*;
public class Main {
static class Product {
String name;
String category;
int price;
Product(String name, String category, int price) {
this.name = name;
this.category = category;
this.price = price;
}
}
public static void main(String[] args) {
List<Product> items = new ArrayList<>();
items.add(new Product("ノートPC", "PC", 128000));
items.add(new Product("デスクトップ", "PC", 98000));
items.add(new Product("マウス", "周辺機器", 3200));
items.add(new Product("キーボード", "周辺機器", 8500));
items.add(new Product("モニター", "周辺機器", 45000));
Map<String, Integer> sumByCategory = new TreeMap<>();
Map<String, Integer> countByCategory = new TreeMap<>();
int total = 0;
for (int i = 0; i < items.size(); i++) {
Product p = items.get(i);
System.out.println((i + 1) + ". " + p.name + "(" + p.category + "):"
+ String.format("%,d", p.price) + "円");
sumByCategory.put(p.category,
sumByCategory.getOrDefault(p.category, 0) + p.price);
countByCategory.put(p.category,
countByCategory.getOrDefault(p.category, 0) + 1);
total += p.price;
}
System.out.println("---");
for (Map.Entry<String, Integer> e : sumByCategory.entrySet()) {
String cat = e.getKey();
System.out.println(cat + ":" + String.format("%,d", e.getValue())
+ "円(" + countByCategory.get(cat) + "件)");
}
System.out.println("---");
System.out.println("合計:" + String.format("%,d", total) + "円");
}
}この集計は、配列だけでは非常に書きにくい。「カテゴリが何種類あるか」が事前に分からないからだ。配列で書くなら、まず全件走査してカテゴリの一覧を作り、その数だけ配列を確保し、それから集計する——3周も必要になる。Map なら1周で済む。
sumByCategory.getOrDefault(p.category, 0) + p.price が集計の核心だ。初めて登場したカテゴリなら0から、2回目以降は既存の値に足す——この1行が、カテゴリの種類を意識せずに集計を成立させている。もし get() を使っていたら、初回は null が返って null + p.price でエラーになっていた。
TreeMap を選んだ理由も明確だ。HashMap では出力順が保証されないため、実行するたびに「PC」と「周辺機器」の順序が入れ替わる可能性がある。テストで期待値と比較するような場面では、これが不具合として現れる。
実務のJavaでは、配列よりも List と Map のほうが圧倒的に多く使われる。件数が動的に変わり、キーで検索する必要があるのが現実のデータだからだ。配列は「サイズが固定で高速性が要る場面」に限られる。
次章では例外処理を学ぶ。ここまで try/catch を断片的に使ってきたが、エラーとどう向き合うかを体系的に扱う。