Java入門⑭ Map ── 名前をつけて、データを引く

前回は、まとまりの中身を全部取り出す拡張for文をやりました。

今回は、データのまとまりの最後。名前をつけてデータを引けるMap(マップ)です。

Map とは、「名前」と「中身」をペアで覚えておくまとまりです。

番号で引くのが、不便なとき

配列や ArrayList は、中身を番号(0,1,2…)で取り出していました。

int[] scores = {80, 95, 70};
System.out.println(scores[1]);   // 95(1番目)

でも、これだと「scores[1] って、誰の点数だっけ?」と分からなくなります。番号と中身の対応を、自分で覚えておかないといけません。

もし「山田さんの点数」のように、名前で引けたら便利ですよね。

"山田" → 80
"田中" → 95

これを実現するのが Map です。「地図(マップ)」というより、ここでは「対応表」と考えると分かりやすい。言葉(名前)から、中身を引く対応表です。

書き方を見てみる

名前と点数のペアを、Map で持ってみます。

import java.util.HashMap;

public class Main {
    public static void main(String[] args) {
        HashMap<String, Integer> scores = new HashMap<String, Integer>();

        scores.put("山田", 80);
        scores.put("田中", 95);
        scores.put("佐藤", 70);
    }
}

HashMap(ハッシュマップ)は、Map のいちばん基本的な種類です。

  • HashMap<String, Integer> … 「文字列の名前」で「整数の中身」を引く
    • < > の中が、左が名前の型、右が中身の型
  • new HashMap<...>() … 空っぽの Map を用意
  • scores.put("山田", 80) … 「山田」という名前に、80 を結びつける

ArrayList は add(追加)でしたが、Map は put(置く) でペアを入れます。

名前で引いてみる

取り出すときは、番号ではなく名前を使います。get です。

System.out.println(scores.get("山田"));   // 80
System.out.println(scores.get("田中"));   // 95

scores.get("山田") で、「山田さんの点数」がすぐ取り出せます。番号を覚える必要はありません。「誰の点数か」が、コードを見ただけで分かります。

配列の scores[1](誰?)と、Map の scores.get("山田")(山田さん!)。この分かりやすさが、Map の強みです。

配列・ArrayList と、どう使い分けるか

  • 配列・ArrayList … 中身を 順番(番号) で管理する。「○番目」で扱う
  • Map … 中身を 名前 で管理する。「○○の値」で扱う

たとえば、

  • 「来た順に並んだ待ち行列」→ 順番が大事なので ArrayList
  • 「社員番号から、名前を引く」→ 名前で引きたいので Map
  • 「商品コードから、値段を引く」→ Map

「番号で十分か、名前で引きたいか」。これが使い分けの判断軸です。

つまずきポイント

学生がはまるのが、存在しない名前で引くことです。

HashMap<String, Integer> scores = new HashMap<String, Integer>();
scores.put("山田", 80);

System.out.println(scores.get("田中"));   // 「田中」は登録していない

Java の Map の場合、登録していない名前で引くと、エラーにはなりませんが null(何も無い) が返ってきます。

この null をそのまま使おうとすると、別のエラーにつながることがあります(C#連載でいう NullReferenceException のような問題)。あるか分からないときは、containsKey で先に確かめると安全です。

if (scores.containsKey("田中")) {
    System.out.println(scores.get("田中"));
}

「田中という名前があれば、引く」。これなら安全です。

まとめ

Map は、名前と中身をペアで持つまとまり。

HashMap<String, Integer> scores = new HashMap<String, Integer>();
scores.put("山田", 80);              // put で入れる
System.out.println(scores.get("山田")); // get で名前から引く
  • 番号ではなく 名前 で取り出せる
  • 入れるのは put、取り出すのは get
  • 順番で扱うなら ArrayList、名前で引くなら Map
  • 無い名前で引くと nullcontainsKey で確認できる

これで、データのまとまり(配列・ArrayList・拡張for文・Map)がひととおり揃いました。次回からは、処理をひとまとめにする メソッド に進みます。