有没有一种像这样初始化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"};
什么是正确的语法?我没有找到任何相关的内容。这是可能的吗?我正在寻找一种将一些“最终/静态”值放入地图中的最短/最快方法,这些值在创建地图时预先知道并且永远不会改变。
如果您只需要一个条目:可以使用Collections.singletonMap("key", "value")
。
是的,现在这是可能的。在Java 9中添加了一些工厂方法来简化创建映射的过程:
// 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。 Map.of
方法定义了最多十个元素的映射,而Map.ofEntries
方法没有这样的限制。mutableMap = new HashMap<>(Map.of("a", "b"));
。还要注意,此情况下键和值必须不为null
。Map<String, String> myMap = new HashMap<String, String>() {{
put("a", "b");
put("c", "d");
}};
然而,匿名子类可能会在某些情况下引入不需要的行为。例如:
使用函数进行初始化也可以让你在初始化器中生成一个 map,但避免了不良副作用:
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()
方法 :) - skwisgaarMap.entry
而不是entry
,但其他方面都可以工作。谢谢! - Cameron Hudson这是一种方式。
Map<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);
ImmutableMap.of
最多适用于5个条目。否则,请使用构建器:源代码。
如果您允许第三方库,您可以使用Guava的ImmutableMap来实现类似字面的简洁:
Map<String, String> test = ImmutableMap.of("k1", "v1", "k2", "v2");
Map<String, String> test = ImmutableMap.<String, String>builder()
.put("k1", "v1")
.put("k2", "v2")
...
.build();
目前(2021年)还没有直接的方法可以做到这一点 - Java没有Map字面量(尽管我认为它们曾计划在Java 8中加入,但并未实现)。
有些人喜欢这样做:
Map<String,String> test = new HashMap<String, String>(){{
put("test","test"); put("test","test");}};
这将创建一个HashMap的匿名子类,它的实例初始化程序会将这些值放入其中。(顺便说一句,映射表不能包含两次相同的值,你的第二个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
设为final... 试一下并在此报告。
自Java 9以来,你还可以使用Map.of(...)和Map.ofEntries()语法,如 yankee 的答案中所解释的。
Map<String,String> test = new HashMap<String, String>()
{
{
put(key1, value1);
put(key2, value2);
}
};
HashMap
硬编码到这个子类中。只有在实际提供它们时才能起作用。(对于一个新的(空)HashMap,类型参数是无关紧要的。) - Paŭlo Ebermann另一种方法是使用普通的Java 7类和可变参数:创建一个名为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...
方法。Map< String , String > animalSounds =
Map.of(
"dog" , "bark" , // key , value
"cat" , "meow" , // key , value
"bird" , "chirp" // key , value
)
;
Map.of
Map.of
静态方法,可以满足你的需求:使用字面语法实例化一个不可变的Map
。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();
Map < DayOfWeek, Person > weekendWorker =
Map.of(
DayOfWeek.SATURDAY , alice , // key , value
DayOfWeek.SUNDAY , bob // key , value
)
;
Map.ofEntries( … )
Map.ofEntries( Map.Entry , … )
接受任意数量实现Map.Entry
接口的对象。Java提供了两个实现该接口的类,一个是可变的,另一个是不可变的: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 )
);
Map.copyOf
Map.copyOf
。传入一个现有的map,返回该map的不可变副本。copyOf
方法将返回对原始对象的引用,而不会创建新的map。Collections.unmodifiableMap
提示:如果需要/期望一个真正的不可变map,请优先使用Map.copyOf
而不是Collections.unmodifiableMap
。
Collections
方法生成的是对原始map的视图,只是一个简单的包装器,而不是真正的副本。好处是节省内存,但缺点是对原始map的修改会反映出来。record Person( String name ) { }
Person alice = new Person ( "Alice" );
Person bob = new Person ( "Bob" );
Map < DayOfWeek, Person > weekendWorkerMutable = HashMap.newHashMap ( 2 );
weekendWorkerMutable.put ( DayOfWeek.SATURDAY , bob );
weekendWorkerMutable.put ( DayOfWeek.SUNDAY , bob );
System.out.println ( "weekendWorkerMutable = " + weekendWorkerMutable );
Map < DayOfWeek, Person > weekendWorkerSupposedlyUnmodifiable = Collections.unmodifiableMap ( weekendWorkerMutable );
System.out.println ( "weekendWorkerSupposedlyUnmodifiable = " + weekendWorkerSupposedlyUnmodifiable );
Map < DayOfWeek, Person > trueCopy = Map.copyOf ( weekendWorkerSupposedlyUnmodifiable );
System.out.println ( "trueCopy = " + trueCopy );
weekendWorkerMutable.put ( DayOfWeek.SATURDAY , alice ); // <--- Modify the original.
System.out.println ( " ----- After mutating the original mutable map ----- " );
System.out.println ( "weekendWorkerSupposedlyUnmodifiable = " + weekendWorkerSupposedlyUnmodifiable );
System.out.println ( "trueCopy = " + trueCopy );
weekendWorkerMutable = {SATURDAY=Person[name=Bob], SUNDAY=Person[name=Bob]}
weekendWorkerSupposedlyUnmodifiable = {SATURDAY=Person[name=Bob], SUNDAY=Person[name=Bob]}
trueCopy = {SUNDAY=Person[name=Bob], SATURDAY=Person[name=Bob]}
----- After mutating the original mutable map -----
weekendWorkerSupposedlyUnmodifiable = {SATURDAY=Person[name=Alice], SUNDAY=Person[name=Bob]}
trueCopy = {SUNDAY=Person[name=Bob], SATURDAY=Person[name=Bob]}
请注意,通过Map.of
创建的映射的迭代顺序是不确定的。条目的顺序是任意的。不要根据所见的顺序编写代码,因为文档警告顺序可能会发生变化。
请注意,所有这些Map.of...
方法返回一个未指定类别的Map
。底层具体类甚至可能在Java的不同版本之间有所变化。这种匿名性使得Java可以从各种实现中选择最适合您特定数据的实现。例如,如果您的键来自枚举,Java可能在内部使用EnumMap
。
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 及其以上版本中,您有更简单的方法来做同样的事情。
Pair.of()
代替new SimpleEntry<>
,然后使用Pair::getKey
和Pair::getValue
。 - Tobias GrunwaldCollectors.toMap
依赖于 Map.merge
,并且不接受空值,因此会抛出一个 NullPointerException
。这在这个错误报告中有所描述: https://bugs.openjdk.java.net/browse/JDK-8148463
同时,如果一个键出现多次,普通的 Collectors.toMap
将会抛出一个 IllegalStateException
。Map<String, String> myMap = Stream.of(
new SimpleEntry<>("key1", "value1"),
new SimpleEntry<>("key2", (String) null),
new SimpleEntry<>("key3", "value3"),
new SimpleEntry<>("key1", "value1updated"))
.collect(HashMap::new,
(map, entry) -> map.put(entry.getKey(),
entry.getValue()),
HashMap::putAll);
entry(...)
比new SimpleEntry<>(...)
更简单(导入java.util.Map.entry
) - MugenMap<String, String> map = MapInit
.init("key1", "value1")
.put("key2", "value2")
.put("key3", "value3")
.getMap();
这个实用类在键和值的类型、条目数量以及生成的 Map 的类型方面都没有限制。
该实用类如下所示:
public class MapInit<K, V, T extends Map<K, V>> {
private final T map;
private MapInit(final T map) {
this.map = map;
}
public T getMap() {
return this.map;
}
public static <K, V> MapInit<K, V, HashMap<K, V>> init(final K key, final V value) {
return init(HashMap::new, key, value);
}
public static <K, V, T extends Map<K, V>> MapInit<K, V, T> init(final Supplier<T> mapSupplier, final K key, final V value) {
return new MapInit<>(mapSupplier.get()) //
.put(key, value);
}
public MapInit<K, V, T> put(final K key, final V value) {
this.map.put(key, value);
return this;
}
}
static
的,而这个问题是问如何通过字面量语法进行实例化。请投票重新开放。也许这个问题与其他问题重复了;如果是这样,请重新开放并通过链接到一个真正源头的问题再次关闭它。 - Basil Bourque