有没有这样初始化Java HashMap的方法?:

Map<String,String> test = 
    new HashMap<String, String>{"test":"test","test":"test"};

正确的语法是什么?我没有发现任何与此相关的信息。这可能吗?我正在寻找最短/最快的方法来将一些“最终/静态”值放在地图中,这些值永远不会改变,并且在创建地图时预先知道。


当前回答

tl;博士

在Java 9和更高版本中使用Map.of…方法。

Map< String , String > animalSounds =
    Map.of(
        "dog"  , "bark" ,   // key , value
        "cat"  , "meow" ,   // key , value
        "bird" , "chirp"    // key , value
    )
;

地图of

Java9添加了一系列Map.of静态方法,以满足您的需要:使用文本语法实例化不可变的Map。

映射(条目集合)是不可变的,因此在实例化后不能添加或删除条目。此外,每个条目的键和值是不可变的,不能更改。有关其他规则,请参见Javadoc,例如不允许NULL,不允许重复键,映射的迭代顺序是任意的。

让我们看看这些方法,使用一些示例数据绘制一张一周中某一天的地图,以显示我们希望该天工作的人。

Person alice = new Person( "Alice" );
Person bob = new Person( "Bob" );
Person carol = new Person( "Carol" );

映射.of()

Map.of创建一个空的Map。无法修改,因此无法添加条目。下面是这样一个地图的示例,空的没有条目。

Map < DayOfWeek, Person > dailyWorkerEmpty = Map.of();

dailyWorkerEmpty.toString():{}

第页,共页(…)

Map.of(k,v,k,v…)是几个方法,需要1到10个键值对。下面是两个条目的示例。

Map < DayOfWeek, Person > weekendWorker = 
        Map.of( 
            DayOfWeek.SATURDAY , alice ,     // key , value
            DayOfWeek.SUNDAY , bob           // key , value
        )
;

weekendWorker.toString():{SUNDAY=人{name=“Bob”},星期六=人{name=“虱子”}}

项目地图(…)

条目的Map.Entries(Map.Entry,…)采用实现Map.Entrey接口的任意数量的对象。Java捆绑了两个实现该接口的类,一个是可变的,另一个是不可变的:AbstractMap.SimpleEntry,AbstractMap.SimpleModuleEntry。但是我们不需要指定具体的类。我们只需要调用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():{星期三=人{name=‘Bob’},星期二=人{name=“Bob”},周四=人{name=‘Carol’}、星期五=人{name=‘Carol‘},周一=人{name=‘虱子’}

地图副本

Java10添加了Map.copyOf方法。传递现有的映射,获取该映射的不可变副本。

笔记

注意,不能保证通过Map.of生成的映射的迭代器顺序。条目具有任意顺序。不要根据看到的顺序编写代码,因为文档警告顺序可能会更改。

注意,所有这些Map.of…方法都返回未指定类的Map。底层的具体类甚至可能因Java的不同版本而异。这种匿名性使Java能够从各种实现中选择最适合您特定数据的实现。例如,如果您的键来自枚举,Java可能会在封面下使用EnumMap。

其他回答

我们使用一个简单的实用程序类以流畅的方式初始化Maps:

Map<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;
    }
}

没有直接的方法可以做到这一点——截至2021,Java没有Map文字(然而,我认为它们是为Java8提出的,但没有实现)。

有些人喜欢这样:

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");

如果测试映射是实例变量,请将初始化放在构造函数或实例初始值设定项中:

Map<String,String> test = new HashMap<String, String>();
{
    test.put("test","test");
    test.put("test1","test2");
}

如果测试映射是类变量,请将初始化放在静态初始值设定项中:

static Map<String,String> test = new HashMap<String, String>();
static {
    test.put("test","test");
    test.put("test1","test2");
}

如果你希望你的映射永远不变,你应该在初始化后用Collections.unmodifiedMap(…)包装你的映射。你也可以在静态初始化器中这样做:

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);
}

(我不确定你现在是否能让考试成为最终……试试看,然后在这里报告。)

从Java9开始,您还拥有Map.of(…)和Map.entries()语法,正如yankee的回答所解释的。

使用Java 8或更低版本

您可以使用静态块用一些值初始化映射。例子:

public static Map<String,String> test = new HashMap<String, String>

static {
    test.put("test","test");
    test.put("test1","test");
}

使用Java 9或更高版本

在声明时,可以使用Map.of()方法用一些值初始化映射。例子:

public static Map<String,String> test = Map.of("test","test","test1","test");

以下代码可以在Java 8中实现此功能:

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

信用:

tl;博士

在Java 9和更高版本中使用Map.of…方法。

Map< String , String > animalSounds =
    Map.of(
        "dog"  , "bark" ,   // key , value
        "cat"  , "meow" ,   // key , value
        "bird" , "chirp"    // key , value
    )
;

地图of

Java9添加了一系列Map.of静态方法,以满足您的需要:使用文本语法实例化不可变的Map。

映射(条目集合)是不可变的,因此在实例化后不能添加或删除条目。此外,每个条目的键和值是不可变的,不能更改。有关其他规则,请参见Javadoc,例如不允许NULL,不允许重复键,映射的迭代顺序是任意的。

让我们看看这些方法,使用一些示例数据绘制一张一周中某一天的地图,以显示我们希望该天工作的人。

Person alice = new Person( "Alice" );
Person bob = new Person( "Bob" );
Person carol = new Person( "Carol" );

映射.of()

Map.of创建一个空的Map。无法修改,因此无法添加条目。下面是这样一个地图的示例,空的没有条目。

Map < DayOfWeek, Person > dailyWorkerEmpty = Map.of();

dailyWorkerEmpty.toString():{}

第页,共页(…)

Map.of(k,v,k,v…)是几个方法,需要1到10个键值对。下面是两个条目的示例。

Map < DayOfWeek, Person > weekendWorker = 
        Map.of( 
            DayOfWeek.SATURDAY , alice ,     // key , value
            DayOfWeek.SUNDAY , bob           // key , value
        )
;

weekendWorker.toString():{SUNDAY=人{name=“Bob”},星期六=人{name=“虱子”}}

项目地图(…)

条目的Map.Entries(Map.Entry,…)采用实现Map.Entrey接口的任意数量的对象。Java捆绑了两个实现该接口的类,一个是可变的,另一个是不可变的:AbstractMap.SimpleEntry,AbstractMap.SimpleModuleEntry。但是我们不需要指定具体的类。我们只需要调用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():{星期三=人{name=‘Bob’},星期二=人{name=“Bob”},周四=人{name=‘Carol’}、星期五=人{name=‘Carol‘},周一=人{name=‘虱子’}

地图副本

Java10添加了Map.copyOf方法。传递现有的映射,获取该映射的不可变副本。

笔记

注意,不能保证通过Map.of生成的映射的迭代器顺序。条目具有任意顺序。不要根据看到的顺序编写代码,因为文档警告顺序可能会更改。

注意,所有这些Map.of…方法都返回未指定类的Map。底层的具体类甚至可能因Java的不同版本而异。这种匿名性使Java能够从各种实现中选择最适合您特定数据的实现。例如,如果您的键来自枚举,Java可能会在封面下使用EnumMap。