このようなJava HashMapを初期化する方法はありますか?:
Map<String,String> test =
new HashMap<String, String>{"test":"test","test":"test"};
正しい構文は何でしょうか?これについては何も見つかりませんでした。これは可能ですか?変更することなく、マップの作成時に事前にわかっている「最終/静的」値をマップに配置するための最短/最速の方法を探しています。
このようなJava HashMapを初期化する方法はありますか?:
Map<String,String> test =
new HashMap<String, String>{"test":"test","test":"test"};
正しい構文は何でしょうか?これについては何も見つかりませんでした。これは可能ですか?変更することなく、マップの作成時に事前にわかっている「最終/静的」値をマップに配置するための最短/最速の方法を探しています。
回答:
たった1つのエントリが必要な場合:がありますCollections.singletonMap("key", "value")
。
はい、これは今可能です。Java 9では、マップの作成を簡素化する2つのファクトリメソッドが追加されました。
// this works for up to 10 elements:
Map<String, String> test1 = Map.of(
"a", "b",
"c", "d"
);
// this works for any number of elements:
import static java.util.Map.entry;
Map<String, String> test2 = Map.ofEntries(
entry("a", "b"),
entry("c", "d")
);
両方の上記の例のtest
とtest2
ちょうど地図を表現する様々な方法を用いて、同じになります。Map.of
ながら、この方法は、マップ内の10個の要素までのために定義されているMap.ofEntries
方法は、そのような制限を持たないであろう。
この場合、結果のマップは不変のマップになることに注意してください。地図を変更可能にしたい場合は、たとえば、mutableMap = new HashMap<>(Map.of("a", "b"));
いいえ、すべての要素を手動で追加する必要があります。匿名サブクラスで初期化子を使用して、構文を少し短くすることができます。
Map<String, String> myMap = new HashMap<String, String>() {{
put("a", "b");
put("c", "d");
}};
ただし、場合によっては、匿名サブクラスが望ましくない動作を引き起こす可能性があります。これには、たとえば次のものが含まれます。
初期化に関数を使用すると、イニシャライザでマップを生成することもできますが、厄介な副作用は回避されます。
Map<String, String> myMap = createMap();
private static Map<String, String> createMap() {
Map<String,String> myMap = new HashMap<String,String>();
myMap.put("a", "b");
myMap.put("c", "d");
return myMap;
}
Collections.singletonMap()
:)
entry
文書化されていますか?
これは片道です。
HashMap<String, String> h = new HashMap<String, String>() {{
put("a","b");
}};
ただし、注意して、上記のコードを理解する必要があります(HashMapから継承する新しいクラスを作成します)。したがって、http://www.c2.com/cgi/wiki?DoubleBraceInitialization で詳細を読む か、単にGuavaを使用する必要があります。
Map<String, Integer> left = ImmutableMap.of("a", 1, "b", 2, "c", 3);
サードパーティのライブラリを許可する場合は、GuavaのImmutableMapを使用して、リテラルのような簡潔さを実現できます。
Map<String, String> test = ImmutableMap.of("k1", "v1", "k2", "v2");
これは最大5つのキーと値のペアで機能します。それ以外の場合は、そのビルダーを使用できます。
Map<String, String> test = ImmutableMap.<String, String>builder()
.put("k1", "v1")
.put("k2", "v2")
...
.build();
これを行う直接的な方法はありません-JavaにはMapリテラルがありません(まだ-Java 8向けに提案されたと思います)。
このような人もいます:
Map<String,String> test = new HashMap<String, String>(){{
put("test","test"); put("test","test");}};
これにより、HashMapの匿名サブクラスが作成され、そのインスタンス初期化子がこれらの値を配置します。(ちなみに、マップに同じ値を2回含めることはできません。2番目のputが最初のputを上書きします。次の例では異なる値を使用します。)
通常の方法はこれです(ローカル変数の場合):
Map<String,String> test = new HashMap<String, String>();
test.put("test","test");
test.put("test1","test2");
あなたの場合はtest
マップがインスタンス変数である、コンストラクタまたはインスタンス初期化子で初期化を置きます:
Map<String,String> test = new HashMap<String, String>();
{
test.put("test","test");
test.put("test1","test2");
}
あなたの場合はtest
マップがクラス変数があり、静的初期化子で初期化を置きます:
static Map<String,String> test = new HashMap<String, String>();
static {
test.put("test","test");
test.put("test1","test2");
}
マップを変更しない場合は、初期化後にでマップをラップする必要がありますCollections.unmodifiableMap(...)
。静的初期化子でもこれを行うことができます:
static Map<String,String> test;
{
Map<String,String> temp = new HashMap<String, String>();
temp.put("test","test");
temp.put("test1","test2");
test = Collections.unmodifiableMap(temp);
}
(test
ファイナルにできるかどうかはわかりません...試して、ここで報告してください。)
Map<String,String> test = new HashMap<String, String>()
{
{
put(key1, value1);
put(key2, value2);
}
};
HashMap
をこのサブクラスにハードコーディングします。これは、実際に提供した場合にのみ機能します。(新しい(空の)HashMapでは、型引数は関係ありません。)
代わりに、プレーンなJava 7クラスとvarargsを使用してHashMapBuilder
、このメソッドでクラスを作成します。
public static HashMap<String, String> build(String... data){
HashMap<String, String> result = new HashMap<String, String>();
if(data.length % 2 != 0)
throw new IllegalArgumentException("Odd number of arguments");
String key = null;
Integer step = -1;
for(String value : data){
step++;
switch(step % 2){
case 0:
if(value == null)
throw new IllegalArgumentException("Null key value");
key = value;
continue;
case 1:
result.put(key, value);
break;
}
}
return result;
}
次のような方法を使用します。
HashMap<String,String> data = HashMapBuilder.build("key1","value1","key2","value2");
Map.of…
Java 9以降のメソッドを使用します。
Map< String , String > animalSounds =
Map.of(
"dog" , "bark" , // key , value
"cat" , "meow" , // key , value
"bird" , "chirp" // key , value
)
;
Map.of
Java 9は一連のMap.of
静的メソッドを追加して、希望どおりの処理を行います。リテラル構文を使用して不変Map
をインスタンス化します。
マップ(エントリのコレクション)は不変なので、インスタンス化後にエントリを追加または削除することはできません。また、各エントリのキーと値は不変であり、変更できません。NULLを許可しない、重複キーを許可しない、マッピングの反復順序は任意など、他のルールについてはJavadocを参照してください。
これらの方法を見てみましょう。サンプルデータを使用して、その日に作業する予定の人に対する曜日のマップのサンプルを使用します。
Person alice = new Person( "Alice" );
Person bob = new Person( "Bob" );
Person carol = new Person( "Carol" );
Map.of()
Map.of
空を作成します Map
。変更できないため、エントリを追加できません。以下は、そのようなマップの例です。エントリはなく、空です。
Map < DayOfWeek, Person > dailyWorkerEmpty = Map.of();
dailyWorkerEmpty.toString():{}
Map.of( … )
Map.of( k , v , k , v , …)
1〜10個のキーと値のペアを取得するいくつかのメソッドがあります。2つのエントリの例を次に示します。
Map < DayOfWeek, Person > weekendWorker =
Map.of(
DayOfWeek.SATURDAY , alice , // key , value
DayOfWeek.SUNDAY , bob // key , value
)
;
weekendWorker.toString():{SUNDAY = Person {name = 'Bob'}、SATURDAY = Person {name = 'Alice'}}
Map.ofEntries( … )
Map.ofEntries( Map.Entry , … )
Map.Entry
インターフェイスを実装する任意の数のオブジェクトを取ります。Javaはそのインターフェイス、1つの不定、他の不変を実装する2つのクラスをバンドル: AbstractMap.SimpleEntry
、AbstractMap.SimpleImmutableEntry
。しかし、具体的なクラスを指定する必要はありません。Map.entry( k , v )
メソッドを呼び出してキーと値を渡すだけで、実装しているクラスのオブジェクトを取得できますMap.Entry
インターフェイスをます。
Map < DayOfWeek, Person > weekdayWorker = Map.ofEntries(
Map.entry( DayOfWeek.MONDAY , alice ) , // Call to `Map.entry` method returns an object implementing `Map.Entry`.
Map.entry( DayOfWeek.TUESDAY , bob ) ,
Map.entry( DayOfWeek.WEDNESDAY , bob ) ,
Map.entry( DayOfWeek.THURSDAY , carol ) ,
Map.entry( DayOfWeek.FRIDAY , carol )
);
weekdayWorker.toString():{WEDNESDAY = Person {name = 'Bob'}、TUESDAY = Person {name = 'Bob'}、THURSDAY = Person {name = 'Carol'}、FRIDAY = Person {name = 'Carol'} 、MONDAY = Person {name = 'Alice'}}
Map.copyOf
Java 10がメソッドを追加しましたMap.copyOf
。既存のマップを渡し、そのマップの不変のコピーを取得します。
を介しMap.of
て作成されたマップの反復子の順序が保証されないことに。エントリには任意の順序があります。ドキュメントでは、注文が変更される可能性があることを警告しているため、表示されている注文に基づいてコードを記述しないでください。
これらのすべてのことに注意してくださいMap.of…
メソッドが返すMap
の不特定のクラス。基礎となる具象クラスは、Javaのバージョンによって異なる場合があります。この匿名性により、Javaは、特定のデータに最適に適合するものであれば、さまざまな実装から選択できます。たとえば、キーがenumからのものである場合、Javaは裏で使用することEnumMap
があります。
Map.of
2つの簡単な方法で、独自の(Java 9以降でのみ利用可能な)メソッドを簡単に作成できます。
例
public <K,V> Map<K,V> mapOf(K k1, V v1, K k2, V v2 /* perhaps more parameters */) {
return new HashMap<K, V>() {{
put(k1, v1);
put(k2, v2);
// etc...
}};
}
特定のパラメータセットに対して多数のメソッドを作成する代わりに、リストを使用してこれを作成することもできます。
例
public <K, V> Map<K, V> mapOf(List<K> keys, List<V> values) {
if(keys.size() != values.size()) {
throw new IndexOutOfBoundsException("amount of keys and values is not equal");
}
return new HashMap<K, V>() {{
IntStream.range(0, keys.size()).forEach(index -> put(keys.get(index), values.get(index)));
}};
}
注 これを使用するたびに匿名クラスが作成されるため、これをすべてに使用することはお勧めしません。
JAVA 8
プレーンJava 8 Streams/Collectors
では、ジョブを実行するために使用する可能性もあります。
Map<String, String> myMap = Stream.of(
new SimpleEntry<>("key1", "value1"),
new SimpleEntry<>("key2", "value2"),
new SimpleEntry<>("key3", "value3"))
.collect(toMap(SimpleEntry::getKey, SimpleEntry::getValue));
これには、匿名クラスを作成しないという利点があります。
インポートは次のとおりです。
import static java.util.stream.Collectors.toMap;
import java.util.AbstractMap.SimpleEntry;
もちろん、他の回答で述べられているように、Java 9以降では、同じことを行う簡単な方法があります。
残念ながら、キーと値のタイプが同じでない場合に可変引数を使用することはObject...
、タイプセーフを完全に使用して失う必要があるため、あまり合理的ではありません。たとえばを常に作成したい場合Map<String, String>
、もちろんa toMap(String... args)
も可能ですが、キーと値を混同するのは簡単で、奇数の引数は無効になるため、あまりきれいではありません。
次のようなチェーン可能なメソッドを持つHashMapのサブクラスを作成できます。
public class ChainableMap<K, V> extends HashMap<K, V> {
public ChainableMap<K, V> set(K k, V v) {
put(k, v);
return this;
}
}
そしてそれを new ChainableMap<String, Object>().set("a", 1).set("b", "foo")
別のアプローチは、一般的なビルダーパターンを使用することです。
public class MapBuilder<K, V> {
private Map<K, V> mMap = new HashMap<>();
public MapBuilder<K, V> put(K k, V v) {
mMap.put(k, v);
return this;
}
public Map<K, V> build() {
return mMap;
}
}
そしてそれを new MapBuilder<String, Object>().put("a", 1).put("b", "foo").build();
ただし、私が時々使用したソリューションでは、可変引数とPair
クラスを使用しています。
public class Maps {
public static <K, V> Map<K, V> of(Pair<K, V>... pairs) {
Map<K, V> = new HashMap<>();
for (Pair<K, V> pair : pairs) {
map.put(pair.first, pair.second);
}
return map;
}
}
Map<String, Object> map = Maps.of(Pair.create("a", 1), Pair.create("b", "foo");
煩わしさはPair.create()
少し気になりますが、これでかなりうまくいきます。静的インポートを気にしない場合は、もちろんヘルパーを作成できます。
public <K, V> Pair<K, V> p(K k, V v) {
return Pair.create(k, v);
}
Map<String, Object> map = Maps.of(p("a", 1), p("b", "foo");
(Pair
を使用することを想像する代わりにMap.Entry
、それはインターフェースであるため、実装クラスまたはヘルパーファクトリメソッド、あるいはその両方が必要です。また、不変ではなく、このタスクに役立つ他のロジックが含まれています。)
Java 8でStreamsを使用できます(これはSetの例です)。
@Test
public void whenInitializeUnmodifiableSetWithDoubleBrace_containsElements() {
Set<String> countries = Stream.of("India", "USSR", "USA")
.collect(collectingAndThen(toSet(), Collections::unmodifiableSet));
assertTrue(countries.contains("India"));
}
参照:https : //www.baeldung.com/java-double-brace-initialization
キーと値のペアを1つだけ配置する必要がある場合は、Collections.singletonMap(key、value);を使用できます。