サーチ…


前書き

java.util.Mapインタフェースは、キーとその値の間のマッピングを表します。マップに重複キーを含めることはできません。各キーは最大で1つの値にマップできます。

Mapはインターフェイスなので、インターフェイスを使用するためには、そのインターフェイスの具体的な実装をインスタンス化する必要があります。いくつかのMap実装があり、主にjava.util.HashMapjava.util.TreeMapが使用されます

備考

マップは、 キーごとに関連するを持つキーを格納するオブジェクトです。キーとその値は、 キー/値のペアまたはエントリと呼ばれることもあります 。通常、マップには次の機能があります。

  • データはキー/値のペアでマップに格納されます。
  • マップには、特定のキーのエントリが1つしか含まれていない場合があります。マップに特定のキーを持つエントリが含まれていて、同じキーを持つ2番目のエントリを格納しようとすると、2番目のエントリが最初のエントリに置き換わります。つまり、これはキーに関連付けられた値を変更します。
  • マップは、キーがマップに存在するかどうかをテストし、キーに関連付けられた値をフェッチし、キーと値のペアを削除するための高速操作を提供します。

最も一般的に使用されるマップ実装はHashMapです。文字列や数字のキーでうまく動作します。

HashMapなどのプレーンマップは順序付けされていません。キーと値のペアを反復することで、個々のエントリを任意の順序で返すことができます。制御された方法でマップエントリを反復処理する必要がある場合は、次を参照する必要があります。

  • TreeMapのようなソートされたマップは、自然順序でキーを反復します(または、 Comparatorを指定することで指定できる順序で)。たとえば、数字をキーとしてソートされたマップは、数値順にその項目を反復することが期待されます。

  • LinkedHashMapは、マップに挿入された順序と同じ順序で、または最近アクセスされた順序でエントリを反復することを許可します。

要素を追加する

  1. 添加
Map<Integer, String> map = new HashMap<>();
map.put(1, "First element."); 
System.out.println(map.get(1));

出力: First element.

  1. オーバーライド
Map<Integer, String> map = new HashMap<>();
map.put(1, "First element.");
map.put(1, "New element.");
System.out.println(map.get(1));

出力: New element.

HashMap例として使用します。 Mapインタフェースを実装する他の実装も同様に使用できます。

複数の項目を追加する

V put(K key,V value)を使うことができます:

このマップ内の指定されたキーに指定された値を関連付けます(オプション)。以前マップにキーのマッピングが含まれていた場合、古い値は指定された値に置き換えられます。

String currentVal;
Map<Integer, String> map = new TreeMap<>();
currentVal = map.put(1, "First element.");
System.out.println(currentVal);// Will print null
currentVal = map.put(2, "Second element.");
System.out.println(currentVal); // Will print null yet again    
currentVal = map.put(2, "This will replace 'Second element'");
System.out.println(currentVal); // will print Second element.
System.out.println(map.size()); // Will print 2 as key having
// value 2 was replaced.

Map<Integer, String> map2 = new HashMap<>();
map2.put(2, "Element 2");
map2.put(3, "Element 3");

map.putAll(map2);

System.out.println(map.size());  

出力:

3

多くの項目を追加するには、次のような内部クラスを使用できます。

Map<Integer, String> map = new HashMap<>() {{
    // This is now an anonymous inner class with an unnamed instance constructor
    put(5, "high");
    put(4, "low");
    put(1, "too slow");
}};

匿名の内部クラスの作成は必ずしも効率的ではなく、メモリリークを招く可能性があるので、可能であれば、代わりにイニシャライザブロックを使用してください。

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

static {
    // Now no inner classes are created so we can avoid memory leaks
    put(5, "high");
    put(4, "low");
    put(1, "too slow");
}

上記の例は、マップを静的にします。また、静的でないコンテキストでも、すべての静的なものを取り除くことで使用できstatic

これに加えて、ほとんどの実装でputAllサポートされています。これは、あるマップのすべてのエントリを次のように別のマップに追加できます。

another.putAll(one);

Java 8からのマップのデフォルトメソッドの使用

マップインタフェースのJava 8で導入されたデフォルトメソッドの使用例

  1. getOrDefaultの使用

キーにマップされた値を返します。キーが存在しない場合は、デフォルト値を返します。

Map<Integer, String> map = new HashMap<>();
map.put(1, "First element");
map.get(1);                                 // => First element
map.get(2);                                 // => null
map.getOrDefault(2, "Default element");     // => Default element
  1. forEachを使用する

各マップエントリで 'アクション'で指定された操作を実行できます

  Map<Integer, String> map = new HashMap<Integer, String>();
  map.put(1, "one");
  map.put(2, "two");
  map.put(3, "three");
  map.forEach((key, value) -> System.out.println("Key: "+key+ " :: Value: "+value));

   // Key: 1 :: Value: one
   // Key: 2 :: Value: two
   // Key: 3 :: Value: three
  1. replaceAllを使用する

キーがある場合のみ新しい値で置き換えられます

 Map<String, Integer> map = new HashMap<String, Integer>();
 map.put("john", 20);
 map.put("paul", 30);
 map.put("peter", 40);
 map.replaceAll((key,value)->value+10);   //{john=30, paul=40, peter=50}
  1. putIfAbsentの使用

キーが存在しないか、またはnullにマップされている場合は、キーと値のペアがマップに追加されます

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("john", 20);
    map.put("paul", 30);
    map.put("peter", 40);
    map.putIfAbsent("kelly", 50);     //{john=20, paul=30, peter=40, kelly=50}
  1. 削除の使用

    指定された値に関連付けられている場合にのみキーを削除します。

     Map<String, Integer> map = new HashMap<String, Integer>();
     map.put("john", 20);
     map.put("paul", 30);
     map.put("peter", 40);
     map.remove("peter",40); //{john=30, paul=40}
    
  2. 置き換えを使用する

    キーが存在する場合、値は新しい値に置き換えられます。キーが存在しない場合、何もしません。

Map<String, Integer> map = new HashMap<String, Integer>();
map.put("john", 20);
map.put("paul", 30);
map.put("peter", 40);
map.replace("peter",50); //{john=20, paul=30, peter=50}
map.replace("jack",60); //{john=20, paul=30, peter=50}
  1. computeIfAbsentの使用

このメソッドは、マップにエントリを追加します。キーは関数で指定され、値はマッピング関数の適用結果です

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("john", 20);
    map.put("paul", 30);
    map.put("peter", 40);
    map.computeIfAbsent("kelly", k->map.get("john")+10); //{john=20, paul=30, peter=40, kelly=30}
    map.computeIfAbsent("peter", k->map.get("john")+10); //{john=20, paul=30, peter=40, kelly=30} //peter already present
  1. computeIfPresent使う

このメソッドは、エントリを追加するか、マップ内の既存のエントリを変更します。そのキーを持つエントリが存在しない場合は何もしません

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("john", 20);
    map.put("paul", 30);
    map.put("peter", 40);
    map.computeIfPresent("kelly", (k,v)->v+10); //{john=20, paul=30, peter=40} //kelly not present
    map.computeIfPresent("peter", (k,v)->v+10); //{john=20, paul=30, peter=50} // peter present, so increase the value 
  1. 計算を使う

このメソッドは、キーの値を新しく計算された値で置き換えます

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("john", 20);
    map.put("paul", 30);
    map.put("peter", 40);
    map.compute("peter", (k,v)->v+50); //{john=20, paul=30, peter=90} //Increase the value 
  1. マージの使用

キーが存在しない場合はキーを値に置き換えます。キーが存在する場合は、新しく計算された値に置き換えます。キーがマップから削除されます。新しい値がnullの場合はマップに追加されます。

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("john", 20);
    map.put("paul", 30);
    map.put("peter", 40);
    
    //Adds the key-value pair to the map, if key is not present or value for the key is null
    map.merge("kelly", 50 , (k,v)->map.get("john")+10); // {john=20, paul=30, peter=40, kelly=50}
    
    //Replaces the value with the newly computed value, if the key is present
    map.merge("peter", 50 , (k,v)->map.get("john")+10); //{john=20, paul=30, peter=30, kelly=50}
   
    //Key is removed from the map , if new value computed is null
    map.merge("peter", 30 , (k,v)->map.get("nancy")); //{john=20, paul=30, kelly=50}

地図をクリアする

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

map.put(1, "First element.");
map.put(2, "Second element.");
map.put(3, "Third element.");

map.clear();

System.out.println(map.size());   // => 0

マップの内容を反復する

マップでは、マップのキー、値、またはキーと値のペアにコレクションとしてアクセスできるメソッドが用意されています。これらのコレクションを反復することができます。たとえば、次のマップを考えます。

Map<String, Integer> repMap = new HashMap<>();
repMap.put("Jon Skeet", 927_654);
repMap.put("BalusC", 708_826);
repMap.put("Darin Dimitrov", 715_567);

マップキーを反復する:

for (String key : repMap.keySet()) {
    System.out.println(key);
}

印刷物:

ダーリン・ディミトロフ
ジョン・スケート
BalusC

keySet()はマップのキーをSetとして提供します。キーは重複する値を含むことができないため、 Setが使用されます。セットを反復すると、順番に各キーが生成されます。 HashMapsは順序付けされていないので、この例ではキーは任意の順序で返されます。

マップ値を反復する:

for (Integer value : repMap.values()) {
    System.out.println(value);
}

印刷物:

715567
927654
708826

values()は、マップの値をCollectionとして返します。コレクションを反復すると、順番に各値が返されます。ここでも、値は任意の順序で返されます。

キーと値を一緒に繰り返す

for (Map.Entry<String, Integer> entry : repMap.entrySet()) {
    System.out.printf("%s = %d\n", entry.getKey(), entry.getValue());
}

印刷物:

ダーリン・ディミトロフ= 715567
ジョン・スケート= 927654
BalusC = 708826

entrySet()は、 Map.Entryオブジェクトのコレクションを返します。 Map.Entryは各エントリのキーと値にアクセスします。

マップのマージ、結合、合成

putAllを使用して、あるマップのすべてのメンバーを別のマップに配置します。マップにすでに存在するキーには、対応する値が上書きされます。

Map<String, Integer> numbers = new HashMap<>();
numbers.put("One", 1)
numbers.put("Three", 3)
Map<String, Integer> other_numbers = new HashMap<>();
other_numbers.put("Two", 2)
other_numbers.put("Three", 4)

numbers.putAll(other_numbers)

これにより、次のようなマッピングがnumbersられnumbers

"One" -> 1
"Two" -> 2
"Three" -> 4 //old value 3 was overwritten by new value 4

値を上書きするのではなく、値を結合する場合は、Java 8で追加されたMap.mergeを使用できます。これは、ユーザー提供のBiFunctionを使用して重複キーの値をマージします。 mergeは個々のキーと値で動作するため、ループまたはMap.forEachを使用する必要があります。ここでは、重複するキーの文字列を連結します。

for (Map.Entry<String, Integer> e : other_numbers.entrySet())
    numbers.merge(e.getKey(), e.getValue(), Integer::sum);
//or instead of the above loop
other_numbers.forEach((k, v) -> numbers.merge(k, v, Integer::sum));

制約を強制する場合は、キーが重複しないようにするには、 AssertionErrorをスローするマージ関数を使用します。

mapA.forEach((k, v) ->
    mapB.merge(k, v, (v1, v2) ->
        {throw new AssertionError("duplicate values for key: "+k);}));

Map <X、Y>とMap <Y、Z>を作成してMap <X、Z>を取得します。

2つのマッピングを作成する場合は、次のように行うことができます

    Map<String, Integer> map1 = new HashMap<String, Integer>();
    map1.put("key1", 1);
    map1.put("key2", 2);
    map1.put("key3", 3);
    
    Map<Integer, Double> map2 = new HashMap<Integer, Double>();
    map2.put(1, 1.0);
    map2.put(2, 2.0);
    map2.put(3, 3.0);

    Map<String, Double> map3 = new new HashMap<String, Double>();
    map1.forEach((key,value)->map3.put(key,map2.get(value)));

これにより、以下のマッピング

    "key1" -> 1.0
    "key2" -> 2.0
    "key3" -> 3.0

キーが存在するかどうかを確認する

Map<String, String> num = new HashMap<>();
num.put("one", "first");

if (num.containsKey("one")) {
    System.out.println(num.get("one")); // => first
}

マップにはNULL値を含めることができます

マップの場合、「キーを含む」と「値を持つ」を混同しないように注意しなければなりません。たとえば、 HashMapはnullが含まれている可能性があります。これは、次のことが完全に正常な動作であることを意味します。

Map<String, String> map = new HashMap<>();
map.put("one", null);
if (map.containsKey("one")) {
    System.out.println("This prints !"); // This line is reached 
}
if (map.get("one") != null) {
    System.out.println("This is never reached !"); // This line is never reached 
}

より正式には、 map.contains(key) <=> map.get(key)!=nullという保証はありませんmap.contains(key) <=> map.get(key)!=null

効率的な地図エントリの反復

このセクションでは、 Map<Integer, Integer>のエントリを繰り返し処理し、 Integer値の合計を生成する10個の固有の実装例のコードとベンチマークを提供します。すべての例はアルゴリズムの複雑さがΘ(n)ですが、実際の環境でどの実装がより効率的であるかについての洞察を提供するのに役立ちます。

  1. Map.Entryを使用したIteratorを使用した実装
    Iterator<Map.Entry<Integer, Integer>> it = map.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry<Integer, Integer> pair = it.next();
        sum += pair.getKey() + pair.getValue();
    }
  1. for Map.Entryを使用for実装
    for (Map.Entry<Integer, Integer> pair : map.entrySet()) {
        sum += pair.getKey() + pair.getValue();
    }
  1. Map.forEach (Java 8+)を使用した実装
    map.forEach((k, v) -> sum[0] += k + v);
  1. for Map.keySetを使った実装
    for (Integer key : map.keySet()) {
        sum += key + map.get(key);
    }
  1. Iteratorを使用したMap.keySetを使用した実装
    Iterator<Integer> it = map.keySet().iterator();
    while (it.hasNext()) {
        Integer key = it.next();
        sum += key + map.get(key);
    }
  1. for IteratorMap.Entryを使った実装
    for (Iterator<Map.Entry<Integer, Integer>> entries = 
             map.entrySet().iterator(); entries.hasNext(); ) {
        Map.Entry<Integer, Integer> entry = entries.next();
        sum += entry.getKey() + entry.getValue();
    }
  1. Stream.forEach (Java 8以上)を使用した実装
    map.entrySet().stream().forEach(e -> sum += e.getKey() + e.getValue());
  1. Stream.forEachStream.parallel (Java 8+)を使用した実装
    map.entrySet()
       .stream()
       .parallel()
       .forEach(e -> sum += e.getKey() + e.getValue());
  1. ApacheコレクションからのIterableMapを使用した実装
    MapIterator<Integer, Integer> mit = iterableMap.mapIterator();
    while (mit.hasNext()) {
        sum += mit.next() + it.getValue();
    }
  1. EclipseコレクションからMutableMapを使用した実装
     mutableMap.forEachKeyValue((key, value) -> {
         sum += key + value;
     });

パフォーマンステストGithubで利用可能なコード
テスト環境:Windows 8.1 64ビット、Intel i7-4790 3.60GHz、16GB

  1. 10回の試行(100要素)の平均性能最高:308±21ns / op

    Benchmark                           Score     Error  Units
    test3_UsingForEachAndJava8            308  ±     21  ns/op
    test10_UsingEclipseMutableMap         309  ±      9  ns/op
    test1_UsingWhileAndMapEntry           380  ±     14  ns/op
    test6_UsingForAndIterator             387  ±     16  ns/op
    test2_UsingForEachAndMapEntry         391  ±     23  ns/op
    test7_UsingJava8StreamAPI             510  ±     14  ns/op
    test9_UsingApacheIterableMap          524  ±      8  ns/op
    test4_UsingKeySetAndForEach           816  ±     26  ns/op
    test5_UsingKeySetAndIterator          863  ±     25  ns/op
    test8_UsingJava8StreamAPIParallel    5552  ±    185  ns/op
    
  2. 10回の試行(10000要素)の平均性能最高:37.606±0.790μs/ op

    Benchmark                           Score     Error  Units
    test10_UsingEclipseMutableMap       37606  ±    790  ns/op
    test3_UsingForEachAndJava8          50368  ±    887  ns/op
    test6_UsingForAndIterator           50332  ±    507  ns/op
    test2_UsingForEachAndMapEntry       51406  ±   1032  ns/op
    test1_UsingWhileAndMapEntry         52538  ±   2431  ns/op
    test7_UsingJava8StreamAPI           54464  ±    712  ns/op
    test4_UsingKeySetAndForEach         79016  ±  25345  ns/op
    test5_UsingKeySetAndIterator        91105  ±  10220  ns/op
    test8_UsingJava8StreamAPIParallel  112511  ±    365  ns/op
    test9_UsingApacheIterableMap       125714  ±   1935  ns/op
    
  3. 10回の試行(100000要素)の平均性能最高:1184.767±332.968μs/ op

    Benchmark                            Score       Error  Units
    test1_UsingWhileAndMapEntry       1184.767  ±  332.968  μs/op
    test10_UsingEclipseMutableMap     1191.735  ±  304.273  μs/op
    test2_UsingForEachAndMapEntry     1205.815  ±  366.043  μs/op
    test6_UsingForAndIterator         1206.873  ±  367.272  μs/op
    test8_UsingJava8StreamAPIParallel 1485.895  ±  233.143  μs/op
    test5_UsingKeySetAndIterator      1540.281  ±  357.497  μs/op
    test4_UsingKeySetAndForEach       1593.342  ±  294.417  μs/op
    test3_UsingForEachAndJava8        1666.296  ±  126.443  μs/op
    test7_UsingJava8StreamAPI         1706.676  ±  436.867  μs/op
    test9_UsingApacheIterableMap      3289.866  ± 1445.564  μs/op
    
  4. マップサイズに対する性能変動の比較

パフォーマンステストのグラフ

       x: Size of Map
    f(x): Benchmark Score (μs/op)

                 100      600     1100     1600     2100
        ---------------------------------------------------
        10  |   0.333    1.631    2.752    5.937    8.024
         3  |   0.309    1.971    4.147    8.147   10.473
         6  |   0.372    2.190    4.470    8.322   10.531
         1  |   0.405    2.237    4.616    8.645   10.707
Tests    2  |   0.376    2.267    4.809    8.403   10.910
 f(x)    7  |   0.473    2.448    5.668    9.790   12.125
         9  |   0.565    2.830    5.952    13.22   16.965
         4  |   0.808    5.012    8.813    13.939  17.407
         5  |   0.81     5.104    8.533    14.064  17.422
         8  |   5.173   12.499   17.351    24.671  30.403

カスタムオブジェクトをキーとして使用する

独自のオブジェクトをキーとして使用する前に、オブジェクトのhashCode()およびequals()メソッドをオーバーライドする必要があります。

単純な場合、あなたは次のようなものを持っています:

class MyKey {
    private String name;
    MyKey(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object obj) {            
        if(obj instanceof MyKey) {
            return this.name.equals(((MyKey)obj).name);
        }
        return false;
    }
    
    @Override
    public int hashCode() {
        return this.name.hashCode();
    }
}

hashCodeは、キーが属するハッシュバケットを決定し、 equalsはそのハッシュバケット内のオブジェクトを決定します。

これらのメソッドがなければ、オブジェクトの参照は上記の比較に使用され、毎回同じオブジェクト参照を使用しなければ機能しません。

HashMapの使用法

HashMapは、Key-Valueペアにデータを格納するデータ構造を提供するMapインタフェースの実装です。

1. HashMapの宣言

Map<KeyType, ValueType> myMap = new HashMap<KeyType, ValueType>();

KeyTypeとValueTypeは、String、Integer、Float、Employee、StudentなどのカスタムクラスのようなJavaの有効な型でなければなりません。

例: Map<String,Integer> myMap = new HashMap<String,Integer>();

2.値をHashMapに入れます。

HashMapに値を入れるには、KeyとValueをパラメータとして渡してHashMapオブジェクトにputメソッドを呼び出さなければなりません。

myMap.put("key1", 1);
myMap.put("key2", 2);

Mapにすでに存在するKeyを使用してputメソッドを呼び出すと、メソッドはその値をオーバーライドして古い値を返します。

3. HashMapから値を取得する。

HashMapから値をgetするには、Keyをパラメータとして渡すことによってgetメソッドを呼び出す必要があります。

myMap.get("key1");    //return 1 (class Integer)

HashMapに存在しないキーを渡すと、このメソッドはnullを返しnull

4.キーがマップ内にあるかどうかを確認します。

myMap.containsKey(varKey);

5.値が地図にあるかどうかを確認します。

myMap.containsValue(varValue);

上記のメソッドは、key、valueがMapに存在するかどうかにかかわらず真または偽のboolean値を返します。

マップの作成と初期化

前書き

Mapsはキーと値のペアが格納されます。各キーには関連する値があります。特定のキーが与えられた場合、マップは関連付けられた値を非常に迅速にルックアップできます。

アソシエート配列とも呼ばれるMapsは、キーと値の形式でデータを格納するオブジェクトです。 Javaでは、マップはコレクションインターフェイスの拡張ではないMapインターフェイスを使用して表されます。

  • 方法1: -

     /*J2SE < 5.0*/
     Map map = new HashMap();
     map.put("name", "A");
     map.put("address", "Malviya-Nagar");
     map.put("city", "Jaipur");
     System.out.println(map);
    
  • 方法2: -

     /*J2SE 5.0+ style (use of generics):*/
     Map<String, Object> map = new HashMap<>();
     map.put("name", "A");
     map.put("address", "Malviya-Nagar");
     map.put("city", "Jaipur");
     System.out.println(map);
    
  • 方法3: -

      Map<String, Object> map = new HashMap<String, Object>(){{
          put("name", "A");
          put("address", "Malviya-Nagar");
          put("city", "Jaipur");
      }};
      System.out.println(map);
    
  • 方法4: -

      Map<String, Object> map = new TreeMap<String, Object>();
          map.put("name", "A");
          map.put("address", "Malviya-Nagar");
          map.put("city", "Jaipur");
      System.out.println(map);
    
  • 方法5: -

      //Java 8
      final Map<String, String> map =
          Arrays.stream(new String[][] {
              { "name", "A" }, 
              { "address", "Malviya-Nagar" }, 
              { "city", "jaipur" },
          }).collect(Collectors.toMap(m -> m[0], m -> m[1]));
      System.out.println(map);
    
  • 方法6: -

      //This way for initial a map in outside the function
      final static Map<String, String> map;
      static
      {
          map = new HashMap<String, String>();
          map.put("a", "b");
          map.put("c", "d");
      }
    
  • Way 7: - 不変の単一キー値マップの作成。

        //Immutable single key-value map
        Map<String, String> singletonMap = Collections.singletonMap("key", "value");
    

    この地図を変更することは不可能であることに注意しください。

    マップを変更しようとすると、UnsupportedOperationExceptionがスローされます。

        //Immutable single key-value pair
        Map<String, String> singletonMap = Collections.singletonMap("key", "value");
        singletonMap.put("newKey", "newValue"); //will throw UnsupportedOperationException
        singletonMap.putAll(new HashMap<>()); //will throw UnsupportedOperationException
        singletonMap.remove("key"); //will throw UnsupportedOperationException
        singletonMap.replace("key", "value", "newValue"); //will throw UnsupportedOperationException
        //and etc
    


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow