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

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

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


当前回答

我们使用一个简单的实用程序类以流畅的方式初始化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;
    }
}

其他回答

您可以创建一个方法来初始化映射,如下例所示:

Map<String, Integer> initializeMap()
{
  Map<String, Integer> ret = new HashMap<>();

  //populate ret
  ...

  return ret;
}

//call
Map<String, Integer> map = initializeMap();

如果它是一个实例变量,那么一个实例初始化块绝对是最好的方法,特别是如果你不能使用Map.of(),因为你需要一个不同类型的映射。

但是,如果你感觉很活泼,你可以使用Java 8供应商(不推荐)。

private final Map<String,Runnable> games = ((Supplier<Map<String,Runnable>>)() -> {
  Map<String,Runnable> map = new LinkedHashMap<>();

  map.put("solarus",this::playSolarus);
  map.put("lichess",this::playLichess);

  return map;
}).get();

或者制作自己的功能界面(我觉得不错):

@FunctionalInterface
public interface MapMaker<M> {
  static <M extends Map<K,V>,K,V> M make(M map,MapMaker<M> maker) {
    maker.build(map);
    return map;
  }

  void build(M map);
}

// Can use LinkedHashMap!
private final Map<String,Runnable> games = MapMaker.make(
    new LinkedHashMap<>(),(map) -> {
      map.put("solarus",this::playSolarus);
      map.put("lichess",this::playLichess);
    });

我们使用一个简单的实用程序类以流畅的方式初始化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;
    }
}

of()似乎最普遍,也最不受限制。这里,它自动处理非对象输入值:

List<Map<String, Object> certs = new ArrayList<>(){{ add( Map.of(
    "TAG",          Obj1 // Object
    "TAGGED_ID",    1L //Long
    "DEGREE",       "PARENT" // String
    "DATE",         LocalDate.now() // LocalDate
));}};

注意,由静态Map.of(..)构造函数创建的映射不允许键和值都为空。

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。