検索

キーワード


【Java】Mapインターフェース<キーとバリューの違い、代表的なクラスの紹介>

  • 公開日:2020-07-30 09:57:49
  • 最終更新日:2021-01-25 18:06:55
【Java】Mapインターフェース<キーとバリューの違い、代表的なクラスの紹介>

こんにちは、駆け出しプログラマーの若江です!

ここでは初学者として学習を終えた私が、アウトプットの意味も込めてコレクションのMapについてご紹介させていただきます。

できる限り初学者が理解しやすい内容として紹介させていただくので、参考となれば幸いです!


関連記事リンク:コレクションの概要 / 拡張for文の使い方 / コレクション (List) の使い方 / コレクション(Set)の使い方 / コレクション(Queue, DeQue)の紹介 / コレクション(Iterator)の紹介

コレクション:Mapインターフェース ~キー・バリュー格納方法と取り出し方~

複数のデータを持つことができるコレクションの中で、

「キー」と「バリュー」で格納したデータを管理する特徴を持つのが Mapインターフェースです。

ここではMapインターフェースの特徴や、Mapインターフェースを実装したクラスの紹介をさせていただきます。


Mapインターフェースとは?

Mapインターフェースを実装したクラスを利用するためにまずはその特徴を確認しておきましょう。

Mapインターフェースには以下の特徴があります。

「キー」と「バリュー」で格納データを管理する。

 「キー」とはオリジナルの名前みたいなもので、同じ名前のキーを重複して設定することができません。

 「バリュー」は和訳の通り値です。重複などの管理がされないため、キーと違って重複データを許可します。

 キーとバリューの関係はペアで、1つのキーに対して1つのバリューが紐づけられます。

 格納したい値(バリュー)に独自の名前(キー)を付けてあげるようなイメージです。

 また、名前(キー)で呼んであげれば値(バリュー)が返事をするような動作をするイメージでもあります。

格納するデータは順序管理されない。

 Mapインターフェース自体には「1番目のデータ」などの管理方法が設計されていません。

 そのため、格納するデータはマップの配列内でバラバラに点在しているイメージです。

 これら点在しているデータをオリジナルの名前(キー)で管理しています。


Mapインターフェースを実装した3つのクラス

ここではMapインターフェースを実装した代表的なクラスを3つ紹介します。

Mapインターフェースを実装したクラスの基本的な書き方は以下の構文です。

Mapインターフェースを実装したクラスの基本的な書き方:

 Map< キーの型, バリューの型 > 変数名 = new Mapインターフェースを実装したクラス < キーの型, バリューの型 >();

※「キーの型」と「バリューの型」はそれぞれ別の型を設定することができます。


それぞれ格納データの管理方法に差がありますので違いを確認しましょう。


HashMapクラス

Mapインターフェースの機能をそのまま実装した最も基本的なクラスです。

「キー」「バリュー」でデータを管理するほか、null も許容します。

実際のサンプルコードで書き方や結果も含めて確認しましょう。

import java.util.Map;
import java.util.HashMap;
// Integer型のキーとString型のバリューを持つHashMapのインスタンスを生成
Map<Integer, String> map = new HashMap<Integer, String>();

// ()内の左側がキー、右側がバリュー
map.put(1, "a"); // キー 1 に バリュー a を紐づけ
map.put(1, "a"); // キー重複
map.put(2, "a"); // キーがオリジナルであれば、バリューは重複データでも許容される
map.put(null, null); // null は許容される

System.out.println(map); // 結果:1=a, 2=a, null=null を表示

※結果の順序は格納するデータにより異なります。


TreeMapクラス

キーの名前を昇順に並べ替えるクラスです。

基本的にHashMapと同じくキーバリュー管理を行いますが、TreeMapクラスは null を許容しません。

サンプルコードで実際の書き方と結果を確認しましょう。

import java.util.Map;
import java.util.TreeMap;
// Integer型のキーとString型のバリューを持つTreeMapのインスタンスを生成
Map<Integer, String> map = new TreeMap<Integer, String>();

map.put(1, "a"); // キー 1 とバリュー a を紐づけ
map.put(1, "a"); // キー重複
map.put(6, "a"); // キー 6 とバリュー a を紐づけ
map.put(3, "c"); // キー 3 とバリュー c を紐づけ
map.put(2, "b"); // キー 2 とバリュー b を紐づけ

map.put(null, null); // null は許容されないため例外を返す

// null の例外を発生させない場合の結果
System.out.println(map); // 結果:1=a, 2=b, 3=c, 6=a を表示 

 ※順序管理ではないのでキー「3」の次が「4」でなくても正常に昇順で並び替えできます。

HashMapと同じくバリューは重複が可能です。


LinkedHashMapクラス

先ほど紹介したHashMapクラスを継承して機能拡張したクラスがLinkedHashMapです。

HashMapの機能に加えてデータを格納した順序で管理する特徴があります。

こちらもサンプルコードで書き方と結果を確認しましょう。

import java.util.Map;
import java.util.LinkedHashMap;
// Integer型のキーとString型のバリューを持つLinkedHashMapのインスタンスを生成
Map<Integer, String> map = new LinkedHashMap<Integer, String>();

map.put(1, "a"); // キー 1 とバリュー a を紐づけ
map.put(1, "a"); // キー重複
map.put(6, "d"); // キー 6 とバリュー d を紐づけ
map.put(3, "c"); // キー 3 とバリュー c を紐づけ
map.put(2, "b"); // キー 2 とバリュー b を紐づけ
map.put(null, null); // null も許容する

System.out.println(map); // 結果:1=a, 6=d, 3=c, 2=b, null=null を表示

入力された順番に結果が表示されました。


キーの重複に関して

Mapではキーの重複が許容されないと紹介させていただきましたが、

実際にはキーが重複した場合、キーに紐づくバリューが更新される設計となっています。

Map<Integer, String> map = new HashMap<Integer, String>();

map.put(1, "a"); // 1 と a を紐づけ
System.out.println(map); // 結果:1=a を表示

map.put(1, "b"); // 1 に対するバリューを b に更新
System.out.println(map); // 結果:1=b を表示

map.put(1, "c"); // 1 に対するバリューを c に更新
System.out.println(map); // 結果:1=c を表示



Mapで使う代表的なメソッド

先ほどの3つのクラスで共通してよく使うメソッドをここで紹介します。

メソッドは大きく分けて3つ、データの「追加」「削除」「検索」を行います。

「追加」「削除」「検索」の動作を具体的にしたメソッドが以下8つとなります。

※以下サンプルコードでは import を省略しています。


         put        :指定したキーと指定したバリューを紐づけてデータを格納します。

         重複キーを指定した場合はバリューの紐づけを更新します。

Map<Integer, String> map = new HashMap<Integer, String>();

map.put(1, "a"); // キー 1 とバリュー a を紐づけ
System.out.println(map); // 結果:1=a を表示

map.put(1, "b"); // キー 1 が重複したためバリューを b に更新
System.out.println(map); // 結果:1=b を表示

map.put(2, "b"); // 新たなキー 2 とバリュー b を紐づけ
System.out.println(map); // 結果:1=b, 2=b を表示


       clear       :マップ内からデータを全て削除します。

Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
System.out.println(map); // マップ内に 1=a, 2=b, 3=c があることを確認

map.clear(); // マップ内のデータを全て削除
System.out.println(map); // 結果:空のマップを表示


containsKey :マップが保持しているキーに対して、指定したキー名が存在した場合に true を返します。

         キーが存在しない場合に false を返します。

Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
System.out.println(map); // マップ内に 1=a, 2=b, 3=c があることを確認

System.out.println(map.containsKey(1)); // 結果:キー名 1 が存在するため true を返す
System.out.println(map.containsKey(4)); // 結果:キー名 4 が存在しないため false を返す


containsValueマップが保持しているバリューに対して、指定したバリュー名が存在した場合に true を返します。

          バリューが存在しない場合に false を返します。

Map<Integer, String> map = new HashMap<Integer, String>();

map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
System.out.println(map); // マップ内に 1=a, 2=b, 3=c があることを確認

System.out.println(map.containsValue("a")); // バリュー a が存在するため true を返す
System.out.println(map.containsValue("d")); // バリュー d が存在しないため false を返す


         get         :マップ内のキーに対して指定したキー名が存在する場合は紐づくバリューを返します。

          指定したキー名が存在しない場合は null を返します。

Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
System.out.println(map); // マップ内に 1=a, 2=b, 3=c があることを確認

System.out.println(map.get(1)); // 結果:キー 1 に紐づくバリュー a を表示
System.out.println(map.get(4)); // 結果:4 のキー名がないため null を表示


     isEmpty     :マップ内にデータが存在しない場合に true を返します。

              データが1つでも存在する場合は false を返します。

Map<Integer, String> map = new HashMap<Integer, String>();

System.out.println(map.isEmpty()); // データを格納する前のマップは空のため true を表示

map.put(1, "a"); // マップにデータを格納
System.out.println(map.isEmpty()); // 1=a のデータが存在するため false を表示

 ※ null=null でもマップに存在すると判定されるため false を返します。


     remove      :マップ内のキーに対して指定したキー名が存在する場合は削除します。

Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
System.out.println(map); // マップ内に 1=a, 2=b, 3=c があることを確認

map.remove(3); // キー名 3 が存在するため削除
System.out.println(map); // 結果:a=1, b=2 を表示


        size        :マップ内に存在するキーの個数を表示します。

Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
map.put(null, null);
System.out.println(map.size()); // 結果:4 を表示 (null もカウント対象)


以上が代表的なメソッドとなります。

これら8つは HashMap, TreeMap, LinkedHashMap 全てのクラスで使うことができます。



余談

上記サンプルコードの「インスタンス生成と putメソッド」を 1つにまとめて記述することもできます。

余裕があれば以下のような書き方ができることも覚えておきましょう。

・インスタン生成と putメソッドをまとめた書き方の例:

 Map< Integer, String> map = new HashMap<Integer, String>(){{ put(1, "a") }};

Map<Integer, String> map = new HashMap<Integer, String>(){
	{
		put(1, "a");
		put(2, "b");
		put(3, "c");
	}
};
System.out.println(map); // 結果:1=a, 2=b, 3=c を表示

※「{{  }}」この書き方はこの場限りのクラスを生成する「匿名クラス」と、

 初期値の「イニシャライザブロック」を利用しています。

 「匿名クラス」と「イニシャライザブロック」に関する紹介は別記事でさせていただきます。



格納したデータの取り出し方

Mapでのデータ操作方法を紹介したので、キーやバリューの取り出し方も併せて確認しておきましょう。

今回は拡張for文とMapインターフェースのメソッド「keySet」と「values」を使って取り出してみます。

keySet:Setインターフェースの重複を許可しない特徴と連動させて、キーの値を取り出します。

values :Collectionインターフェースと連動させて、バリューの値を取り出します。

Map<Integer, String> map = new HashMap<Integer, String>();
map.put(1, "a");
map.put(2, "b");
map.put(3, "c");
map.put(null, null);

// keySet を使ってキーの値を取り出す
for(Integer key : map.keySet()) {
	System.out.println(key); // 結果:1 2 3 を表示
}

// values を使ってバリューの値を取り出す
for(String value : map.values()) {
	System.out.println(value); // 結果:a b c を表示
}



まとめ

「キー」「バリュー」の特徴を持つMapインターフェースと HashMap, TreeMap, LinkedHashMapクラスを紹介しました。

それぞれのクラスではデータの管理方法に違いがあります。

各クラスの役割を状況に応じて使い分けましょう。


関連記事リンク

コレクションの概要 / 拡張for文の紹介 / コレクション (List) の紹介 / コレクション(Set)の紹介 / コレクション(Queue, DeQue)の紹介 / コレクション(Iterator)の紹介


【著者】

若江

30代で異業種となるIT業界へ転職した駆け出しのプログラマです。これまで主に Java や Ruby、HTML/CSS を使って学習を目的としたショップサイトや掲示板サイトの作成を行いました。プログラマとしての経験が浅いからこそ、未経験者の目線に近い形で基礎の紹介をしていきたいと思います。

よく読まれている記事
【Java】JSPでタグライブラリを使う(JSTL)

【Java】JSPでタグライブラリを使う(JSTL)

こんにちは。エンジニアの新田です!ここでは、システムエンジニアとして働いている私が、システム開発手法や開発言語について紹介していこうと思います。今回は、JSPの標準タグライブラリ「JSTL」について紹介します。Javaについて勉強している方、Webアプリケーションを構築したいと思っている方の参考になれば幸いです!関連記事リンク: 【Java】JSPの基本的な構文/【Java】JSPのアクションタグ

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

【Java】Stringクラス文字列を操作するメソッドの使い方まとめ!実例も紹介!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!そもそもStringとは何?『 String 』... Java言語において文字列のデータ型を指します。基本デ

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

【Java】文字列の置き換え(String#format)!エスケープシーケンスのまとめも!!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!Stringクラスformatメソッドの文字列整形【java.utilパッケージ】Formatterクラスfo

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

【Java】文字列格納後に変更可能!?StringBufferクラスとStringBuilderクラス!

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者にも✅、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!文字列を扱う3つのクラス【java.langパッケージ】java.langパッケージの文字列を扱うクラスにはS

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

【Java】値?変数?型??しっかり解説!『データ型(プリミティブ型と参照型)』

こんにちは。新人エンジニアのサトウです。システムエンジニアとして駆け出したばかりですが、初心者なりの視点でわかりやすい記事を心がけていますので参考になればうれしいです。プログラム初心者✅にも、プログラムに興味がある人✨も、短い時間で簡単にできますのでぜひこの記事を読んで試してみてください!プリミティブ型と参照型プログラム開発では型を持った変数を使ってデータのやり取りをしますが、データ型によって仕様