如何初始化静态Map?

如何在Java中初始化静态Map

方法一:静态初始化器
方法二:实例初始化器(匿名子类)或其他方法?

各自的优点和缺点是什么?

下面是一个说明这两种方法的示例:

import java.util.HashMap;import java.util.Map;
public class Test {private static final Map<Integer, String> myMap = new HashMap<>();static {myMap.put(1, "one");myMap.put(2, "two");}
private static final Map<Integer, String> myMap2 = new HashMap<>(){{put(1, "one");put(2, "two");}};}
987929 次浏览

第二种方法的一个优点是,您可以用Collections.unmodifiableMap()包装它,以保证以后不会更新集合:

private static final Map<Integer, String> CONSTANT_MAP =Collections.unmodifiableMap(new HashMap<Integer, String>() \{\{put(1, "one");put(2, "two");}});
// later on...
CONSTANT_MAP.put(3, "three"); // going to throw an exception!

如果需要,第二种方法可以调用protected方法。这对于初始化构造后不可变的类很有用。

实例初始化器在这种情况下只是语法糖,对吧?我不明白为什么你需要一个额外的匿名类来初始化。如果创建的类是Final,它也不会工作。

您也可以使用静态初始化器创建不可变映射:

public class Test {private static final Map<Integer, String> myMap;static {Map<Integer, String> aMap = ....;aMap.put(1, "one");aMap.put(2, "two");myMap = Collections.unmodifiableMap(aMap);}}

在这种情况下,我永远不会创建匿名子类。如果你想使映射不可修改,静态初始化器也同样有效,例如:

private static final Map<Integer, String> MY_MAP;static{Map<Integer, String>tempMap = new HashMap<Integer, String>();tempMap.put(1, "one");tempMap.put(2, "two");MY_MAP = Collections.unmodifiableMap(tempMap);}

我喜欢匿名类的语法;它只是代码更少。然而,我发现的一个主要缺点是,你将无法通过远程来序列化该对象。你会得到一个异常,无法在远程端找到匿名类。

你正在创建的匿名类运行良好。然而,你应该意识到这是一个内部类,因此,它将包含对周围类实例的引用。所以你会发现你不能用它做某些事情(使用XStream作为一个)。你会得到一些非常奇怪的错误。

话虽如此,只要你知道,那么这种方法就可以了。我大部分时间都用它来以简洁的方式初始化各种集合。

编辑:在注释中正确指出这是一个静态类。显然我没有仔细阅读这一点。然而,我的注释仍然适用于匿名内部类。

我做了一些不同的事情。不是最好的,但它对我有用。也许它可以被“泛化”。

private static final Object[][] ENTRIES =\{\{new Integer(1), "one"},{new Integer(2), "two"},};private static final Map myMap = newMap(ENTRIES);
private static Map newMap(Object[][] entries){Map map = new HashMap();
for (int x = 0; x < entries.length; x++){Object[] entry = entries[x];
map.put(entry[0], entry[1]);}
return map;}

也许查看谷歌收藏很有趣,例如他们页面上的视频。它们提供了各种初始化map和set的方法,并提供不可变的集合。

更新:这个库现在被命名为番石榴

我会使用:

public class Test {private static final Map<Integer, String> MY_MAP = createMap();
private static Map<Integer, String> createMap() {Map<Integer, String> result = new HashMap<>();result.put(1, "one");result.put(2, "two");return Collections.unmodifiableMap(result);}}
  1. 它避免了匿名类,我个人认为这是一种糟糕的风格,并避免
  2. 使map的创建更加清晰
  3. 它使地图不可修改
  4. 因为MY_MAP是常数我就叫它常数

Java5提供了这种更紧凑的语法:

static final Map<String , String> FLAVORS = new HashMap<String , String>() \{\{put("Up",    "Down");put("Charm", "Strange");put("Top",   "Bottom");}};
public class Test {private static final Map<Integer, String> myMap;static {Map<Integer, String> aMap = ....;aMap.put(1, "one");aMap.put(2, "two");myMap = Collections.unmodifiableMap(aMap);}}

如果我们声明了多个常量,那么代码将被写入静态块中,将来很难维护。所以最好使用匿名类。

public class Test {
public static final Map numbers = Collections.unmodifiableMap(new HashMap(2, 1.0f)\{\{put(1, "one");put(2, "two");}});}

并且建议对常量使用不可修改的Map,否则它不能被视为常量。

我强烈建议使用“双括号初始化”风格而不是静态块风格。

有人可能会评论说他们不喜欢匿名类、开销、性能等。

但我更多考虑的是代码的易读性和可运维性。从这个角度来看,我认为双括号是一种更好的代码风格,而不是静态方法。

  1. 元素是嵌套和内联的。
  2. 它更多的是OO,而不是程序。
  3. 性能影响很小,可以忽略不计。
  4. 更好的IDE大纲支持(而不是许多匿名静态{}块)
  5. 你保存了几行评论来给他们带来关系。
  6. 防止来自异常和字节码优化器的未初始化对象的可能元素泄漏/实例铅。
  7. 不用担心静态块的执行顺序。

此外,如果您知道匿名类的GC,您始终可以使用new HashMap(Map map)将其转换为普通的HashMap。

你可以这样做,直到你遇到另一个问题。如果你这样做了,你应该为此使用另一种完整的编码风格(例如没有静态、工厂类)。

我喜欢初始化静态、不可变map的番石榴方式:

static final Map<Integer, String> MY_MAP = ImmutableMap.of(1, "one",2, "two");

如您所见,它非常简洁(因为#0中的工厂方法很方便)。

如果您希望地图包含超过5个条目,则不能再使用ImmutableMap.of()。相反,请按照以下行尝试#1

static final Map<Integer, String> MY_MAP = ImmutableMap.<Integer, String>builder().put(1, "one").put(2, "two")// ....put(15, "fifteen").build();

要了解有关Guava不可变集合实用程序的更多好处,请参阅Guava用户指南中解释的不可变集合

(一个子集)Guava曾经被称为谷歌收藏。如果你还没有在你的Java项目中使用这个库,我建议你尝试一下!Guava已经迅速成为Java最受欢迎和最有用的免费第三方库之一,作为用户同意。(如果你是新手,这个链接后面有一些很好的学习资源。)


更新(2015):至于Java8,好吧,我仍然会使用Guava方法,因为它比其他任何方法都干净得多。如果你不想要Guava依赖项,请考虑普通的初始化方法。如果你问我,二维数组和Stream API的黑客行为非常丑陋,如果你需要创建一个键和值不相同类型的Map(如问题中的Map<Integer, String>),则会变得更丑陋。

至于番石榴的未来,关于Java8,路易斯·瓦瑟曼说这早在2014年,[更新]在2016年宣布番石榴21将需要并适当支持Java8


更新(2016):作为便利工厂方法4508760">Tagir Valeev指出,Java9最终将通过为集合添加便利工厂方法来使这一切变得干净,只使用纯JDK:

static final Map<Integer, String> MY_MAP = Map.of(1, "one",2, "two");

我不喜欢静态初始化器语法,也不相信匿名子类。一般来说,我同意使用静态初始化器的所有缺点和使用匿名子类的所有缺点,这些缺点在以前的答案中提到过。另一方面,这些帖子中提出的优点对我来说还不够。我更喜欢使用静态初始化方法:

public class MyClass {private static final Map<Integer, String> myMap = prepareMap();
private static Map<Integer, String> prepareMap() {Map<Integer, String> hashMap = new HashMap<>();hashMap.put(1, "one");hashMap.put(2, "two");
return hashMap;}}

使用Eclipse集合,以下所有操作都有效:

import java.util.Map;
import org.eclipse.collections.api.map.ImmutableMap;import org.eclipse.collections.api.map.MutableMap;import org.eclipse.collections.impl.factory.Maps;
public class StaticMapsTest{private static final Map<Integer, String> MAP =Maps.mutable.with(1, "one", 2, "two");
private static final MutableMap<Integer, String> MUTABLE_MAP =Maps.mutable.with(1, "one", 2, "two");

private static final MutableMap<Integer, String> UNMODIFIABLE_MAP =Maps.mutable.with(1, "one", 2, "two").asUnmodifiable();

private static final MutableMap<Integer, String> SYNCHRONIZED_MAP =Maps.mutable.with(1, "one", 2, "two").asSynchronized();

private static final ImmutableMap<Integer, String> IMMUTABLE_MAP =Maps.mutable.with(1, "one", 2, "two").toImmutable();

private static final ImmutableMap<Integer, String> IMMUTABLE_MAP2 =Maps.immutable.with(1, "one", 2, "two");}

您还可以使用Eclipse集合静态初始化原始映射。

import org.eclipse.collections.api.map.primitive.ImmutableIntObjectMap;import org.eclipse.collections.api.map.primitive.MutableIntObjectMap;import org.eclipse.collections.impl.factory.primitive.IntObjectMaps;
public class StaticPrimitiveMapsTest{private static final MutableIntObjectMap<String> MUTABLE_INT_OBJ_MAP =IntObjectMaps.mutable.<String>empty().withKeyValue(1, "one").withKeyValue(2, "two");
private static final MutableIntObjectMap<String> UNMODIFIABLE_INT_OBJ_MAP =IntObjectMaps.mutable.<String>empty().withKeyValue(1, "one").withKeyValue(2, "two").asUnmodifiable();
private static final MutableIntObjectMap<String> SYNCHRONIZED_INT_OBJ_MAP =IntObjectMaps.mutable.<String>empty().withKeyValue(1, "one").withKeyValue(2, "two").asSynchronized();
private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP =IntObjectMaps.mutable.<String>empty().withKeyValue(1, "one").withKeyValue(2, "two").toImmutable();
private static final ImmutableIntObjectMap<String> IMMUTABLE_INT_OBJ_MAP2 =IntObjectMaps.immutable.<String>empty().newWithKeyValue(1, "one").newWithKeyValue(2, "two");}

备注:我是Eclipse集合的提交者

如果你想要一些简洁且相对安全的东西,你可以将编译时类型检查转移到运行时:

static final Map<String, Integer> map = MapUtils.unmodifiableMap(String.class, Integer.class,"cat",  4,"dog",  2,"frog", 17);

此实现应该捕获任何错误:

import java.util.HashMap;
public abstract class MapUtils{private MapUtils() { }
public static <K, V> HashMap<K, V> unmodifiableMap(Class<? extends K> keyClazz,Class<? extends V> valClazz,Object...keyValues){return Collections.<K, V>unmodifiableMap(makeMap(keyClazz,valClazz,keyValues));}
public static <K, V> HashMap<K, V> makeMap(Class<? extends K> keyClazz,Class<? extends V> valClazz,Object...keyValues){if (keyValues.length % 2 != 0){throw new IllegalArgumentException("'keyValues' was formatted incorrectly!  "+ "(Expected an even length, but found '" + keyValues.length + "')");}
HashMap<K, V> result = new HashMap<K, V>(keyValues.length / 2);
for (int i = 0; i < keyValues.length;){K key = cast(keyClazz, keyValues[i], i);++i;V val = cast(valClazz, keyValues[i], i);++i;result.put(key, val);}
return result;}
private static <T> T cast(Class<? extends T> clazz, Object object, int i){try{return clazz.cast(object);}catch (ClassCastException e){String objectName = (i % 2 == 0) ? "Key" : "Value";String format = "%s at index %d ('%s') wasn't assignable to type '%s'";throw new IllegalArgumentException(String.format(format, objectName, i, object.toString(), clazz.getSimpleName()), e);}}}

我喜欢匿名类,因为它很容易处理:

public static final Map<?, ?> numbers = Collections.unmodifiableMap(new HashMap<Integer, String>() \{\{put(1, "some value");//rest of code here}});

如果您可以使用String表示您的数据,这也是Java8中的一个选项:

static Map<Integer, String> MAP = Stream.of("1=one","2=two").collect(Collectors.toMap(k -> Integer.parseInt(k.split("=")[0]), v -> v.split("=")[1]));

现在Java8已经出来了,这个问题值得重新审视。我尝试了一下——看起来也许你可以利用lambda表达式语法来获得一个非常漂亮和简洁(但类型安全)的map文字语法,如下所示:

Map<String,Object> myMap = hashMap(bob -> 5,TheGimp -> 8,incredibleKoolAid -> "James Taylor",heyArnold -> new Date());
Map<String,Integer> typesafeMap = treeMap(a -> 5,bee -> 8,sea -> 13deep -> 21);

未经测试的示例代码在https://gist.github.com/galdosd/10823529会好奇别人对此的看法(这有点邪恶…)

我更喜欢使用静态初始化器来避免生成匿名类(这将没有进一步的用途),所以我将列出使用静态初始化器初始化的提示。所有列出的解决方案/技巧都是类型安全的。

备注:这个问题没有说任何关于使地图不可修改的事情,所以我将省略它,但要知道它可以很容易地用Collections.unmodifiableMap(map)完成。

第一个提示

第一个技巧是,您可以对地图进行本地引用,并给它一个简短的名称:

private static final Map<Integer, String> myMap = new HashMap<>();static {final Map<Integer, String> m = myMap; // Use short name!m.put(1, "one"); // Here referencing the local variable which is also faster!m.put(2, "two");m.put(3, "three");}

第二个技巧

第二个技巧是您可以创建一个辅助方法来添加条目;如果您想:

private static final Map<Integer, String> myMap2 = new HashMap<>();static {p(1, "one"); // Calling the helper method.p(2, "two");p(3, "three");}
private static void p(Integer k, String v) {myMap2.put(k, v);}

不过,这里的helper方法是不可重用的,因为它只能向myMap2添加元素。为了使其可重用,我们可以将map本身设为helper方法的参数,但这样初始化代码就不会更短了。

第三个技巧

第三个技巧是您可以创建一个具有填充功能的可重用的类似构建器的辅助类。这实际上是一个简单的10行辅助类,它是类型安全的:

public class Test {private static final Map<Integer, String> myMap3 = new HashMap<>();static {new B<>(myMap3)   // Instantiating the helper class with our map.p(1, "one").p(2, "two").p(3, "three");}}
class B<K, V> {private final Map<K, V> m;
public B(Map<K, V> m) {this.m = m;}
public B<K, V> p(K k, V v) {m.put(k, v);return this; // Return this for chaining}}

这是一个Java8单行静态map初始化器:

private static final Map<String, String> EXTENSION_TO_MIMETYPE =Arrays.stream(new String[][] \{\{ "txt", "text/plain" },{ "html", "text/html" },{ "js", "application/javascript" },{ "css", "text/css" },{ "xml", "application/xml" },{ "png", "image/png" },{ "gif", "image/gif" },{ "jpg", "image/jpeg" },{ "jpeg", "image/jpeg" },{ "svg", "image/svg+xml" },}).collect(Collectors.toMap(kv -> kv[0], kv -> kv[1]));

编辑:要像问题中那样初始化Map<Integer, String>,你需要这样的东西:

static final Map<Integer, String> MY_MAP = Arrays.stream(new Object[][]\{\{1, "one"},{2, "two"},}).collect(Collectors.toMap(kv -> (Integer) kv[0], kv -> (String) kv[1]));

编辑(2):i_am_zero有一个更好的、支持混合类型的版本,它使用new SimpleEntry<>(k, v)调用流。查看答案:https://stackoverflow.com/a/37384773/3950982

当我有一个抽象类的具体实现时,我喜欢使用静态初始化器“技术”,该抽象类定义了一个初始化构造函数,但没有默认构造函数,但我希望我的子类有一个默认构造函数。

例如:

public abstract class Shape {
public static final String COLOR_KEY = "color_key";public static final String OPAQUE_KEY = "opaque_key";
private final String color;private final Boolean opaque;
/*** Initializing constructor - note no default constructor.** @param properties a collection of Shape properties*/public Shape(Map<String, Object> properties) {color = ((String) properties.getOrDefault(COLOR_KEY, "black"));opaque = (Boolean) properties.getOrDefault(OPAQUE_KEY, false);}
/*** Color property accessor method.** @return the color of this Shape*/public String getColor() {return color;}
/*** Opaque property accessor method.** @return true if this Shape is opaque, false otherwise*/public Boolean isOpaque() {return opaque;}}

以及我对这个类的具体实现——但它需要/需要一个默认构造函数:

public class SquareShapeImpl extends Shape {
private static final Map<String, Object> DEFAULT_PROPS = new HashMap<>();
static {DEFAULT_PROPS.put(Shape.COLOR_KEY, "yellow");DEFAULT_PROPS.put(Shape.OPAQUE_KEY, false);}
/*** Default constructor -- intializes this square to be a translucent yellow*/public SquareShapeImpl() {// the static initializer was useful here because the call to// this(...) must be the first statement in this constructor// i.e., we can't be mucking around and creating a map herethis(DEFAULT_PROPS);}
/*** Initializing constructor -- create a Square with the given* collection of properties.** @param props a collection of properties for this SquareShapeImpl*/public SquareShapeImpl(Map<String, Object> props) {super(props);}}

然后要使用这个默认构造函数,我们只需:

public class StaticInitDemo {
public static void main(String[] args) {
// create a translucent, yellow square...Shape defaultSquare = new SquareShapeImpl();
// etc...}}

我已经阅读了答案,我决定写我自己的地图建设者。随意复制粘贴和享受。

import java.util.Collections;import java.util.HashMap;import java.util.Map;
/*** A tool for easy creation of a map. Code example:<br/>* {@code MapBuilder.of("name", "Forrest").and("surname", "Gump").build()}* @param <K> key type (inferred by constructor)* @param <V> value type (inferred by constructor)* @author Vlasec (for http://stackoverflow.com/a/30345279/1977151)*/public class MapBuilder <K, V> {private Map<K, V> map = new HashMap<>();
/** Constructor that also enters the first entry. */private MapBuilder(K key, V value) {and(key, value);}
/** Factory method that creates the builder and enters the first entry. */public static <A, B> MapBuilder<A, B> mapOf(A key, B value) {return new MapBuilder<>(key, value);}
/** Puts the key-value pair to the map and returns itself for method chaining */public MapBuilder<K, V> and(K key, V value) {map.put(key, value);return this;}
/*** If no reference to builder is kept and both the key and value types are immutable,* the resulting map is immutable.* @return contents of MapBuilder as an unmodifiable map.*/public Map<K, V> build() {return Collections.unmodifiableMap(map);}}

编辑:最近,我经常发现公共静态方法of,我有点喜欢它。我将其添加到代码中并将构造函数设为私有,从而切换到静态工厂方法模式。

EDIT2:甚至最近,我不再喜欢称为of的静态方法,因为它在使用静态导入时看起来很糟糕。我将其重命名为mapOf,使其更适合静态导入。

我没有看到我使用的方法(并且已经喜欢)发布在任何答案中,所以这里是:

我不喜欢使用静态初始化器,因为它们很笨重,我不喜欢匿名类,因为它为每个实例创建一个新类。

相反,我更喜欢看起来像这样的初始化:

map(entry("keyA", "val1"),entry("keyB", "val2"),entry("keyC", "val3"));

不幸的是,这些方法不是标准Java库的一部分,因此,您需要创建(或使用)一个定义以下方法的实用程序库:

 public static <K,V> Map<K,V> map(Map.Entry<K, ? extends V>... entries)public static <K,V> Map.Entry<K,V> entry(K key, V val)

(您可以使用“导入静态”来避免需要为方法名称加上前缀)

我发现为其他集合(list、set、sortedSet、sortedMap等)提供类似的静态方法很有用。

它不像json对象初始化那么好,但就易读性而言,它是朝着这个方向迈出的一步。

在Java8中,过程方法也可以包含在Supplier中:

Map<String,String> m = ((Supplier<Map<String,String>>)(() -> {Map<String,String> result = new HashMap<>();result.put("foo","hoo");...return result;)).get();

这只是假设的方式,但如果你真的需要一行代码,它可以派上用场。

像往常一样,apache-Commons有正确的方法MapUtils.putAll(Map, Object[])

例如,创建一个颜色映射:

Map<String, String> colorMap = MapUtils.putAll(new HashMap<String, String>(), new String[][] \{\{"RED", "#FF0000"},{"GREEN", "#00FF00"},{"BLUE", "#0000FF"}});

在Java8中,我开始使用以下模式:

private static final Map<String, Integer> MAP = Stream.of(new AbstractMap.SimpleImmutableEntry<>("key1", 1),new AbstractMap.SimpleImmutableEntry<>("key2", 2)).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

这不是最简洁的,有点迂回,但是

  • 它不需要java.util之外的任何东西
  • 它是类型安全的,可以轻松容纳不同类型的键和值。

Map.ofJava9+

private static final Map<Integer, String> MY_MAP = Map.of(1, "one", 2, "two");

有关详细信息,请参阅jep269。JDK 9在2017年9月达到了普遍可用性

这里有一些很好的答案,但我想再提供一个。

创建自己的静态方法来创建和初始化Map。我在一个包中有自己的CollectionUtils类,我在项目中使用,我经常使用各种实用程序,这些实用程序对我来说很容易编写,避免了对一些更大的库的依赖。

这是我的newMap方法:

public class CollectionUtils {public static Map newMap(Object... keyValuePairs) {Map map = new HashMap();if ( keyValuePairs.length % 2 == 1 ) throw new IllegalArgumentException("Must have even number of arguments");for ( int i=0; i<keyValuePairs.length; i+=2 ) {map.put(keyValuePairs[i], keyValuePairs[i + 1]);}return map;}}

用法:

import static CollectionUtils.newMap;// ...Map aMap = newMap("key1", 1.23, "key2", 2.34);Map bMap = newMap(objKey1, objVal1, objKey2, objVal2, objKey3, objVal3);// etc...

它不使用泛型,但是你可以按照你的意愿对地图进行类型转换(只要确保你正确地对它进行类型转换!)

Map<String,Double> aMap = (Map<String,Double>)newMap("key1", 1.23, "key2", 2.34);

由于Java不支持map字面量,因此必须始终显式实例化和填充map实例。

幸运的是,可以使用工厂方法来近似地图文字在Java中的行为。

例如:

public class LiteralMapFactory {
// Creates a map from a list of entries@SafeVarargspublic static <K, V> Map<K, V> mapOf(Map.Entry<K, V>... entries) {LinkedHashMap<K, V> map = new LinkedHashMap<>();for (Map.Entry<K, V> entry : entries) {map.put(entry.getKey(), entry.getValue());}return map;}// Creates a map entrypublic static <K, V> Map.Entry<K, V> entry(K key, V value) {return new AbstractMap.SimpleEntry<>(key, value);}
public static void main(String[] args) {System.out.println(mapOf(entry("a", 1), entry("b", 2), entry("c", 3)));}}

输出:

{a=1, b=2, c=3}

这比一次创建和填充一个元素的map要方便得多。

jep269为集合API提供了一些方便的工厂方法。此工厂方法不在当前的Java版本(8)中,但计划Java9版本。

对于Map,有两种工厂方法:ofofEntries。使用of,您可以传递交替的键/值对。例如,为了创建像{age: 27, major: cs}这样的Map

Map<String, Object> info = Map.of("age", 27, "major", "cs");

目前of有十个重载版本,因此您可以创建一个包含十个键/值对的映射。如果您不喜欢这种限制或交替键/值,您可以使用ofEntries

Map<String, Object> info = Map.ofEntries(Map.entry("age", 27),Map.entry("major", "cs"));

ofofEntries都将返回不可变的Map,因此您无法在构造后更改它们的元素。您可以使用JDK 9早期访问尝试这些功能。

Java9

我们可以使用#0,调用#1来创建每个条目。

import static java.util.Map.entry;private static final Map<Integer,String> map = Map.ofEntries(entry(1, "one"),entry(2, "two"),entry(3, "three"),entry(4, "four"),entry(5, "five"),entry(6, "six"),entry(7, "seven"),entry(8, "eight"),entry(9, "nine"),entry(10, "ten"));

我们也可以使用Map.of,正如Tagir在他的答案这里中建议的那样,但我们不能有超过10个条目使用Map.of

Java8

我们可以创建一个映射条目流。我们已经在java.util.AbstractMap中有两个Entry的实现,分别是简单入口//简化不可变项。对于这个例子,我们可以使用前者作为:

import java.util.AbstractMap.*;private static final Map<Integer, String> myMap = Stream.of(new SimpleEntry<>(1, "one"),new SimpleEntry<>(2, "two"),new SimpleEntry<>(3, "three"),new SimpleEntry<>(4, "four"),new SimpleEntry<>(5, "five"),new SimpleEntry<>(6, "six"),new SimpleEntry<>(7, "seven"),new SimpleEntry<>(8, "eight"),new SimpleEntry<>(9, "nine"),new SimpleEntry<>(10, "ten")).collect(Collectors.toMap(SimpleEntry::getKey, SimpleEntry::getValue));            

这是我最喜欢的如果我

  • 不想(或不能)使用Guava的ImmutableMap.of()
  • 或者我需要一个可变的Map
  • 或者我需要超过JDK9+中Map.of()中的10个条目限制
public static <A> Map<String, A> asMap(Object... keysAndValues) {return new LinkedHashMap<String, A>() \{\{for (int i = 0; i < keysAndValues.length - 1; i++) {put(keysAndValues[i].toString(), (A) keysAndValues[++i]);}}};}

它非常紧凑,它忽略了杂散值(即没有值的最终键)。

用法:

Map<String, String> one = asMap("1stKey", "1stVal", "2ndKey", "2ndVal");Map<String, Object> two = asMap("1stKey", Boolean.TRUE, "2ndKey", new Integer(2));

这是算术软件的代码

Map<Integer, String> map = N.asMap(1, "one", 2, "two");// Or for Immutable mapImmutableMap<Integer, String> = ImmutableMap.of(1, "one", 2, "two");

声明:我是AbacusUtil的开发者。

即使使用Guava的漂亮的ImMutableMap类,有时我也想流利地构建一个可变映射。发现自己想要避免静态块和匿名子类型的东西,当Java8出现时,我写了一个名为Fluent的小库来帮助。

// simple usage, assuming someMap is a Map<String, String> already declaredMap<String, String> example = new Fluent.HashMap<String, String>().append("key1", "val1").append("key2", "val2").appendAll(someMap);

使用默认Java8接口,我可以为所有标准的JavaMap实现(即HashMap、Con当前SkipListMap等)实现Fluent. Map方法,而无需重复。

不可修改的地图也很简单。

Map<String, Integer> immutable = new Fluent.LinkedHashMap<String, Integer>().append("one", 1).append("two", 2).append("three", 3).unmodifiable();

有关源代码、留档和示例,请参阅https://github.com/alexheretic/fluent

如果您只需要向map添加一个值,您可以使用Collections.singleton地图

Map<K, V> map = Collections.singletonMap(key, value)

你的第二种方法(双括号初始化)被认为是反模式,所以我会选择第一种方法。

初始化静态Map的另一种简单方法是使用此实用函数:

public static <K, V> Map<K, V> mapOf(Object... keyValues) {Map<K, V> map = new HashMap<>(keyValues.length / 2);
for (int index = 0; index < keyValues.length / 2; index++) {map.put((K)keyValues[index * 2], (V)keyValues[index * 2 + 1]);}
return map;}
Map<Integer, String> map1 = mapOf(1, "value1", 2, "value2");Map<String, String> map2 = mapOf("key1", "value1", "key2", "value2");

注意:在Java 9中,您可以使用Map.of

您可以使用仙人掌中的#0#1

private static final Map<String, String> MAP = new StickyMap<>(new MapEntry<>("name", "Jeffrey"),new MapEntry<>("age", "35"));

嗯…我喜欢枚举;)

enum MyEnum {ONE   (1, "one"),TWO   (2, "two"),THREE (3, "three");
int value;String name;
MyEnum(int value, String name) {this.value = value;this.name = name;}
static final Map<Integer, String> MAP = Stream.of( values() ).collect( Collectors.toMap( e -> e.value, e -> e.name ) );}

如果你想要不可修改的map,最后java 9添加了一个很酷的工厂方法ofMap接口。类似的方法也添加到Set、List中。

Map<String, String> unmodifiableMap = Map.of("key1", "value1", "key2", "value2");

注意:这个答案实际上属于问题如何直接初始化HashMap(以文字方式)?,但由于在撰写本文时这是这个问题的标记为重复


在Java9的Map.of()之前(也仅限于10个映射),您可以扩展您选择的Map实现,例如:

public class InitHashMap<K, V> extends HashMap<K, V>

重新实现HashMap的构造函数:

public InitHashMap() {super();}
public InitHashMap( int initialCapacity, float loadFactor ) {super( initialCapacity, loadFactor );}
public InitHashMap( int initialCapacity ) {super( initialCapacity );}
public InitHashMap( Map<? extends K, ? extends V> map ) {super( map );}

并添加一个受Aerthel的回答启发但通过使用Object...<K, V>类型是通用的附加构造函数:

public InitHashMap( final Object... keyValuePairs ) {
if ( keyValuePairs.length % 2 != 0 )throw new IllegalArgumentException( "Uneven number of arguments." );
K key = null;int i = -1;
for ( final Object keyOrValue : keyValuePairs )switch ( ++i % 2 ) {case 0:  // keyif ( keyOrValue == null )throw new IllegalArgumentException( "Key[" + (i >>> 1) + "] is <null>." );key = (K) keyOrValue;continue;case 1:  // valueput( key, (V) keyOrValue );}}

运行

public static void main( final String[] args ) {
final Map<Integer, String> map = new InitHashMap<>( 1, "First", 2, "Second", 3, "Third" );System.out.println( map );}

产出

{1=First, 2=Second, 3=Third}

您还可以同样扩展Map接口:

public interface InitMap<K, V> extends Map<K, V> {
static <K, V> Map<K, V> of( final Object... keyValuePairs ) {
if ( keyValuePairs.length % 2 != 0 )throw new IllegalArgumentException( "Uneven number of arguments." );
final Map<K, V> map = new HashMap<>( keyValuePairs.length >>> 1, .75f );K key = null;int i = -1;
for ( final Object keyOrValue : keyValuePairs )switch ( ++i % 2 ) {case 0: // keyif ( keyOrValue == null )throw new IllegalArgumentException( "Key[" + (i >>> 1) + "] is <null>." );key = (K) keyOrValue;continue;case 1: // valuemap.put( key, (V) keyOrValue );}return map;}}

运行

public static void main( final String[] args ) {
System.out.println( InitMap.of( 1, "First", 2, "Second", 3, "Third" ) );}

产出

{1=First, 2=Second, 3=Third}

这一个使用Apache Commons-lang,它很可能已经在您的类路径上:

Map<String, String> collect = Stream.of(Pair.of("hello", "world"),Pair.of("abc", "123"),Pair.of("java", "eight")).collect(Collectors.toMap(Pair::getKey, Pair::getValue));

Java8:

    private static final Map<String, TemplateOpts> templates = new HashMap<>();
static {Arrays.stream(new String[][]\{\{CUSTOMER_CSV, "Plantilla cliente", "csv"}}).forEach(f -> templates.put(f[0], new TemplateOpts(f[1], f[2])));}

它也可以是一个Object[][],将任何东西放在里面并将其映射到for每个循环中