【本サイトではGoogleアドセンス、または、アフィリエイト広告を利用しています。】
Mapとは?
Map(マップ)とは、Javaに標準で用意されているインターフェースの1つです。
1つのデータが持つ複数の情報を1つの変数に保存して
様々な操作を行うことができます。
Mapは、前回お話したListと同様にコレクションクラスの1つです。
「java.util」という名前のパッケージに定義されていて、
インポートすることで使えるようになります。
Mapのイメージとして、例えば、以下のような
1つのオブジェクトに紐づく複数のデータをプログラムで保持する場合
を考えてみましょう。
項目 | 値 |
---|---|
名前 | ジョニー |
性別 | 男 |
年齢 | 30 |
出身 | USA |
生年月日 | 1993/1/1 |
ジョニーさんの情報をプログラムで扱う場合、以下のような方法が考えられます。
① クラス「ジョニー」を作成して情報毎に各フィールドを定義する。
② 配列「ジョニー」を作成して各要素に情報を順番に入れる。
③ リスト「ジョニー」を作成して各要素に情報を順番に入れる。
①だと、ボビーさんやジェシカさんが現れた時に、
どんどんクラスが増えてしまいます。
②や③だと、名前は要素の何番目に入っているだとか、
対応表をどこかにメモしておく必要があります。
どれも微妙ですよね?
そんな時に役に立つのがMapです!
Mapでは、1つの情報を
Key(キー:項目)とValue(バリュー:値)のセットで管理します。
この例では、5つの情報セットができます。
現実世界でも名前や年齢のセットが別々に物体として存在するわけではありません。
ジョニーさんの持つ情報として、名前や年齢があります。
Mapを使えば、複数の情報セットを
1つのオブジェクトの中にまとめて保存しておくことができます。
ジョニーさんの個人情報をプログラム上1つのMapとして扱えるわけです。
HashMapとは?
HashMap(ハッシュマップ)とは、
Javaに標準で用意されているマップを扱うクラスの1つです。
Mapインターフェースを実装しており、
複数の情報セットを1つのオブジェクトに管理して操作する際は
基本的にHashMapをインスタンス化して使います。
(Mapはインターフェースなので、単体ではインスタンス化して使えません。)
HashMapには、情報セットの追加、削除、コピーなど
Mapを扱う際に便利な様々なメソッドが用意されています!
では、今からサンプルコードとあわせて使い方を説明していきます!
マップの宣言
Mapは以下の形で宣言します。
Mapインターフェースの変数に、HashMapを代入する①の方法と、
通常通り、HashMapの変数に、HashMapを代入する②の方法があります。
Map<キーの型, バリューの型> マップの名前 = new HashMap<キーの型, バリューの型>();
HashMap<キーの型, バリューの型> マップの名前 = new HashMap<キーの型, バリューの型>();
また、Map、HashMapを使う為には、
使用するクラスの先頭に以下のインポート宣言が必要です。
import java.util.HashMap;
import java.util.Map;
用途によって2つの宣言方法を変えていくのですが、基本的には①で大丈夫です。
インターフェース型のMapでHashMapを受ける理由としては、
マップの型はHashMapだけではなく、他にもMapインターフェースを実装している
様々なクラスが用意されており、状況に従って、
Mapを他のクラスに変換しやすくする為です。
ただし、HashMapが持つ固有のメソッドは①の宣言では使えないので、
(Mapインターフェースが持つメソッドしか使えない。)
HashMapが持つ固有のメソッドを使いたい場合は、
②の方法で宣言するといった使い方をする必要があります。
マップで扱うジェネリクスについて
宣言する際に使う「<>」ジェネリクスについては、
リストを宣言する時にも登場しましたが、マップの時は宣言方法が少し違います。
マップには、キーとバリューのセットで情報を扱うので、
それぞれのデータ型をカンマ区切りで指定する必要があります。
ジェネリクスの詳細は以下で説明していますので、あわせて読んでみてください。
マップに情報を保存する(put)
マップに情報を保存する時は、「put」メソッド使います。
Map<String, String> infoMap = new HashMap<String, String>();
infoMap.put("name", "ジョニー");
infoMap.put("age", "30");
infoMap.put("country", "USA");
これでinfoMapマップに、
ジョニーさんの「名前」「年齢」「出身」の3つの情報が追加されます。
マップに情報をputする時は、ジェネリクスで指定した型に気をつけましょう。
マップの情報を取り出す・参照する・アクセスする(get)
マップ内にある情報は、「get」メソッドで取得することができます。
引数にputする時に使用したキー項目を指定して使います。
マップから名前を取得して出力してみましょう。
Map<String, String> infoMap = new HashMap<String, String>();
infoMap.put("name", "ジョニー");
infoMap.put("age", "30");
infoMap.put("country", "USA");
System.out.println(infoMap.get("name"));
実行結果は以下です。
ジョニー
キー「name」にセットしたバリュー「ジョニー」が取得できました。
マップの情報を削除する(remove)
マップ内にある情報は、「remove」メソッドで削除できます。
Map<String, String> infoMap = new HashMap<String, String>();
infoMap.put("name", "ジョニー");
infoMap.put("age", "30");
infoMap.put("country", "USA");
infoMap.remove("name");
キーを指定することで、特定の情報を削除できます。
例の場合はマップから名前を削除するので「name」を指定しています。
マップに保存されている情報数を調べる(size)
マップに入っている情報の数は「size」メソッドで取得できます。
Map<String, String> infoMap = new HashMap<String, String>();
infoMap.put("name", "ジョニー");
infoMap.put("age", "30");
infoMap.put("country", "USA");
System.out.println(infoMap.size());
実行結果は以下です。
3
値はint型で返ってくるので、int型の変数に代入して使うこともできます。
マップの情報単位でループする
ループ構文を使って、マップの中に入っている情報を
順番に操作する方法は以下です。
まずは、for文を使ってみます。
マップの中のキー情報は、「keySet」メソッドで取得できます。
また、取得したキー情報は1つにまとまったデータになっているので、
「toArray」メソッドで分解して配列にすることで順番にキーを取得できます。
あとはループする毎にマップにキーを渡していくことで
キーに対応した情報を順番に取得できます。
また、ループする回数はキーの数を「size」で取得して使います。
Map<String, String> infoMap = new HashMap<String, String>();
infoMap.put("name", "ジョニー");
infoMap.put("age", "30");
infoMap.put("country", "USA");
for (int i = 0; i < infoMap.size(); i++) {
String key = (String) infoMap.keySet().toArray()[i];
String value = infoMap.get(key);
System.out.println(key + ":" + value);
}
実行結果は以下です。
country:USA
name:ジョニー
age:30
また、Mapに用意されているforEachメソッドを使うと、
この処理は以下のように1行で書くことができます。
infoMap.forEach((key, value) -> System.out.println(key + ":" + value));
forEachメソッドの中はラムダ式と呼ばれる構文を使います。
書き方としては以下のようになります。
マップ名.forEach((繰り返し処理で使うキーの名前, 繰り返し処理で使うバリューの名前) -> 繰り返し処理);
繰り返し処理は、「{}」で囲うことで複数処理を記載できます。
また、繰り返し処理の中で使うマップのキーとバリューの名前を
変数として「->」の前に指定します。
例えば、複数処理を書く場合はこんな感じです。
infoMap.forEach((key, value) -> {
System.out.println("キー「" + key + "」");
System.out.println("バリュー「" + value + "」");
});
実行結果は以下です。
キー「country」
バリュー「USA」
キー「name」
バリュー「ジョニー」
キー「age」
バリュー「30」
forEachを使うことで、for文より見た目としては
シンプルなプログラムにはなりますが、メンテナンス性は下がります。
無理にforEach(ラムダ式)を使わず、for文を使ってループ処理をしましょう!
マップを初期化する
マップの初期化方法として、以下の書き方をすることで
宣言する時に同時に情報をセットすることもできます。
Map<String, String> infoMap = new HashMap<String, String>() {
{
put("name", "ジョニー");
put("age", "30");
put("country", "USA");
}
};
既にマップにセットする情報が決まっている時に使いましょう。
マップのソートについて
マップの情報を並び替える場合は、マップのまま強引にソートするのではなく、
リスト、もしくは、配列に変換してしまいましょう!
キーを配列にする方法は先ほど述べた通り「keySet」を取得後、
「toArray」メソッドを使います。
バリューを配列にする方法は、
ループ処理で紹介したサンプルコードの出力処理を
配列に順番に代入していく形に書き換えれば実現できます。
そこからソート用に新規作成したリストにaddして変換すれば
前回紹介した方法でソートできます。
特定の情報を持っているか調べる(containsKey、containsValue)
マップに特定の情報が入っているかどうかを調べるには、
「containsKey」または「containsValue」メソッドを使います。
名前の通り、キーの中を検索する時は「containsKey」、
バリューの中を検索する時は「containsValue」を使います。
Map<String, String> infoMap = new HashMap<String, String>() {
{
put("name", "ジョニー");
put("age", "30");
put("country", "USA");
}
};
System.out.println(infoMap.containsKey("name"));
System.out.println(infoMap.containsValue("ボビー"));
実行結果は以下です。
true
false
戻り値はboolean型です。マップに指定の情報がある場合は「true」
ない場合は「false」が返ってきます。
マップをコピーする(clone)
マップをコピーするには、HashMapクラスの「clone」メソッドを使います。
Mapに「clone」メソッドはないので、
HashMapとして変数を宣言する必要があることに注意しましょう。
HashMap<String, String> infoMap = new HashMap<String, String>() {
{
put("name", "ジョニー");
put("age", "30");
put("country", "USA");
}
};
// マップをコピー
HashMap<String, String> copyMap = (HashMap<String, String>) infoMap.clone();
// コピーしたマップに生年月日を追加
copyMap.put("birth", "1993/01/01");
System.out.println("【infoMapの情報】");
infoMap.forEach((key, value) -> System.out.println(key + ":" + value));
System.out.println("【copyMapの情報】");
copyMap.forEach((key, value) -> System.out.println(key + ":" + value));
コピーしたマップは、Object型としてcloneメソッドから返ってくるので、
コピー元の型にあわせて「()」でキャストして代入する必要があります。
コピーしたマップに新たに生年月日の情報を追加してから、
コピー元、コピーマップそれぞれの中身を出力してみました。
【infoMapの情報】
country:USA
name:ジョニー
age:30
【copyMapの情報】
name:ジョニー
country:USA
birth:1993/01/01
age:30
コピー元のマップの中身に影響させることなく、
コピーマップに新たな情報を追加できている部分もポイントの1つです。
マップの中を空にする(clear)
マップの中を空にするには、Mapの「clear」メソッドを使います。
HashMap<String, String> infoMap = new HashMap<String, String>() {
{
put("name", "ジョニー");
put("age", "30");
put("country", "USA");
}
};
System.out.println("クリア前の情報数は「" + infoMap.size() + "」です。");
infoMap.clear();
System.out.println("クリア後の情報数は「" + infoMap.size() + "」です。");
実行結果は以下です。
クリア前の情報数は「3」です。
クリア後の情報数は「0」です。
マップをリストに追加して使う
マップをリストと組み合わせて使うことで、
以下のようなデータベースもプログラム上で簡単に取り扱いできます。
名前 | 年齢 | 出身 |
---|---|---|
ジョニー | 30 | USA |
太郎 | 58 | 日本 |
では、上記の名簿情報をリストにして出力してみましょう!
package example;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
// クラス:メイン処理実行用
public class Example {
// メイン処理
public static void main(String[] args) {
// 名簿リスト
List<Map<String, String>> infoList = new ArrayList<Map<String, String>>();
// ジョニーさんの情報
Map<String, String> infoMap1 = new HashMap<String, String>() {
{
put("name", "ジョニー");
put("age", "30");
put("country", "USA");
}
};
// 太郎さんの情報
Map<String, String> infoMap2 = new HashMap<String, String>() {
{
put("name", "太郎");
put("age", "58");
put("country", "日本");
}
};
// リストにマップを追加
infoList.add(infoMap1);
infoList.add(infoMap2);
// 名簿リスト出力
infoList.forEach(infoMap -> {
System.out.println("【" + infoMap.get("name") + "さんの情報】");
infoMap.forEach((key, value) -> System.out.println(key + ":" + value));
});
}
}
実行結果は以下です。
【ジョニーさんの情報】
country:USA
name:ジョニー
age:30
【太郎さんの情報】
country:日本
name:太郎
age:58
表と同じ情報をListとMapで保持できました!
Listを宣言する時のジェネリクスですが、Listに使うジェネリクスとは別に、
Mapの宣言にもジェネリクスが必要なので、入れ子になっていることもポイントです。
また、出力処理の部分はforEachを使いましたが、
for文で書くとどうなるか余裕がある人はチャレンジしてみてください!
マップの使い方 まとめ
JavaのMapについて以下説明しました。
・Mapについて
・HashMapについて
・マップで定義するジェネリクスについて
・マップの宣言方法
・情報の追加(put)、参照(get)、削除(remove)
・情報数を調べる方法(size)
・マップの情報単位でループする方法(for、forEach)
・マップの初期化
・マップのソート
・情報の検索(containsKey、containsValue)
・マップのコピー(clone)
・マップのクリア(clear)
・マップをリストに追加して使う
マップは複雑なデータを取り扱う際に最もよく使うクラスです。
さらにリストと組合せることで、
簡易的なデータベースとしての役割を持たせることもできます。
データ操作をマスターする為に、
いつでもマップを使いこなせる状態にしておきましょう!