1. 概要

このチュートリアルでは、JavaでHashMapを初期化するさまざまな方法について学習します。

Java8とJava9を使用します。

2. 静的HashMapの静的初期化子

コードのstaticブロックを使用して、HashMapを初期化できます。

public static Map<String, String> articleMapOne;
static {
    articleMapOne = new HashMap<>();
    articleMapOne.put("ar01", "Intro to Map");
    articleMapOne.put("ar02", "Some article");
}

この種の初期化の利点は、マップが変更可能であるということですが、静的に対してのみ機能します。 したがって、エントリは必要に応じて追加および削除できます。

先に進んでテストしてみましょう:

@Test
public void givenStaticMap_whenUpdated_thenCorrect() {
    
    MapInitializer.articleMapOne.put(
      "NewArticle1", "Convert array to List");
    
    assertEquals(
      MapInitializer.articleMapOne.get("NewArticle1"), 
      "Convert array to List");  
}

二重中括弧構文を使用してマップを初期化することもできます。

Map<String, String> doubleBraceMap  = new HashMap<String, String>() {{
    put("key1", "value1");
    put("key2", "value2");
}};

この初期化手法は、使用するたびに匿名の追加クラスを作成し、囲んでいるオブジェクトへの非表示の参照を保持し、メモリリークの問題を引き起こす可能性があるため、回避する必要があることに注意してください。

3. Javaコレクションの使用

単一のエントリでシングルトンの不変マップを作成する必要がある場合、 Collections.singletonMap()は非常に便利です。

public static Map<String, String> createSingletonMap() {
    return Collections.singletonMap("username1", "password1");
}

ここのマップは不変であり、さらにエントリを追加しようとすると、java.lang.UnsupportedOperationException。がスローされることに注意してください。

Collections.emptyMap():を使用して、不変の空のマップを作成することもできます。

Map<String, String> emptyMap = Collections.emptyMap();

4. Java 8 Way

このセクションでは、Java 8 StreamAPIを使用してマップを初期化する方法を見てみましょう。

4.1. Collectors.toMap()を使用する

2次元のString配列のStreamを使用して、それらをマップに収集してみましょう。

Map<String, String> map = Stream.of(new String[][] {
  { "Hello", "World" }, 
  { "John", "Doe" }, 
}).collect(Collectors.toMap(data -> data[0], data -> data[1]));

ここで、キーのデータ型とMapの値が同じであることに注意してください。

より一般的にするために、オブジェクトの配列を取得して、同じ操作を実行してみましょう。

 Map<String, Integer> map = Stream.of(new Object[][] { 
     { "data1", 1 }, 
     { "data2", 2 }, 
 }).collect(Collectors.toMap(data -> (String) data[0], data -> (Integer) data[1]));

その結果、キーのマップを String として作成し、値をIntegerとして作成します。

4.2. Map.Entryのストリームを使用する

ここでは、のインスタンスを使用します Map.Entry。 これは、異なるキーと値のタイプがある別のアプローチです。

まず、SimpleEntryEntryインターフェースの実装を使用しましょう。

Map<String, Integer> map = Stream.of(
  new AbstractMap.SimpleEntry<>("idea", 1), 
  new AbstractMap.SimpleEntry<>("mobile", 2))
  .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

次に、SimpleImmutableEntryの実装を使用してマップを作成しましょう。

Map<String, Integer> map = Stream.of(
  new AbstractMap.SimpleImmutableEntry<>("idea", 1),    
  new AbstractMap.SimpleImmutableEntry<>("mobile", 2))
  .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

4.3. 不変マップの初期化

特定のユースケースでは、不変のマップを初期化する必要があります。 これは、 Collectors.toMap() Collectors.collectingAndThen()内にラップすることで実行できます。

Map<String, String> map = Stream.of(new String[][] { 
    { "Hello", "World" }, 
    { "John", "Doe" },
}).collect(Collectors.collectingAndThen(
    Collectors.toMap(data -> data[0], data -> data[1]), 
    Collections::<String, String> unmodifiableMap));

Streams、を使用したこのような初期化は使用しないでください。パフォーマンスのオーバーヘッドが大きくなり、マップを初期化するためだけに大量のガベージオブジェクトが作成される可能性があります。

5. Java 9 Way

Java 9には、不変マップの作成と初期化を簡素化するMapインターフェースのさまざまなファクトリメソッドが付属しています。

先に進んで、これらのファクトリメソッドを調べてみましょう。

5.1.  Map.of()

このファクトリメソッドは、引数なし、単一の引数、および変数引数を取ります。

Map<String, String> emptyMap = Map.of();
Map<String, String> singletonMap = Map.of("key1", "value");
Map<String, String> map = Map.of("key1","value1", "key2", "value2");

このメソッドは、最大10のキーと値のペアのみをサポートすることに注意してください。

5.2. Map.ofEntries()

Map.of()に似ていますが、キーと値のペアの数に制限はありません。

Map<String, String> map = Map.ofEntries(
  new AbstractMap.SimpleEntry<String, String>("name", "John"),
  new AbstractMap.SimpleEntry<String, String>("city", "budapest"),
  new AbstractMap.SimpleEntry<String, String>("zip", "000000"),
  new AbstractMap.SimpleEntry<String, String>("home", "1231231231")
);

ファクトリメソッドは不変のマップを生成するため、変更するとUnsupportedOperationException。になることに注意してください。

また、nullキーや重複キーは許可されません。

これで、初期化後に変更可能なマップまたは拡大するマップが必要な場合は、 Map インターフェイスの実装を作成し、これらの不変のマップをコンストラクターに渡すことができます。

Map<String, String> map = new HashMap<String, String> (
  Map.of("key1","value1", "key2", "value2"));
Map<String, String> map2 = new HashMap<String, String> (
  Map.ofEntries(
    new AbstractMap.SimpleEntry<String, String>("name", "John"),    
    new AbstractMap.SimpleEntry<String, String>("city", "budapest")));

6. グアバの使用

コアJavaの使用方法を調べたので、先に進み、Guavaライブラリを使用してマップを初期化します。

Map<String, String> articles 
  = ImmutableMap.of("Title", "My New Article", "Title2", "Second Article");

これにより、不変のマップが作成され、変更可能なマップが作成されます。

Map<String, String> articles 
  = Maps.newHashMap(ImmutableMap.of("Title", "My New Article", "Title2", "Second Article"));

メソッドImmutableMap.of()にも、最大5ペアのキー値パラメーターを受け取ることができるオーバーロードされたバージョンがあります。 2組のパラメーターを使用した例は次のようになります。

ImmutableMap.of("key1", "value1", "key2", "value2");

7. 結論

この記事では、 Map を初期化するさまざまな方法、特に空のシングルトンの不変および可変のマップを作成する方法について説明しました。 ご覧のとおり、Java 9以降、この分野で大きな改善が見られます。 

いつものように、サンプルソースコードはGithubプロジェクトにあります。 Java 9の例はここにあり、Guavaサンプルはここにあります。