如何初始化静态地图?

时间:2009-02-03 15:41:33

标签: java dictionary collections initialization idiomatic

如何在Java中初始化静态Map

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

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

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

import java.util.HashMap;
import java.util.Map;

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

    private static final Map<Integer, String> myMap2 = new HashMap<Integer, String>(){
        {
            put(1, "one");
            put(2, "two");
        }
    };
}

42 个答案:

答案 0 :(得分:1029)

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

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

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

答案 1 :(得分:410)

我喜欢Guava初始化静态不可变映射的方法:

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

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

如果您希望地图的条目数超过5个,则无法再使用ImmutableMap.of()。相反,请按以下方式尝试ImmutableMap.builder()

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

要了解有关Guava不可变集合实用程序的好处的更多信息,请参阅Immutable Collections Explained in Guava User Guide

(其中一部分)Guava过去被称为 Google Collections 。如果您尚未在Java项目中使用此库,我强烈建议您尝试使用它! Guava已经迅速成为Java中最受欢迎和最有用的免费第三方库之一,fellow SO users agree。 (如果您是新手,那么该链接背后有一些优秀的学习资源。)


更新(2015):至于 Java 8 ,我仍然会使用Guava方法,因为它比其他任何方式更清洁。如果您不想要番石榴依赖,请考虑plain old init method。如果你问我,two-dimensional array and Stream API的hack非常丑陋,如果你需要创建一个键和值不是同一类型的Map(如问题中的Map<Integer, String>),那就更难看了。

至于番石榴的未来,关于Java 8,Louis Wasserman said this早在2014年,[更新]在2016年宣布Guava 21 will require and properly support Java 8


更新(2016):作为Tagir Valeev points out Java 9 最终会使用纯JDK,只需添加{{3}对于集合:

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

答案 2 :(得分:170)

我会用:

public class Test {
    private static final Map<Integer, String> MY_MAP = createMap();

    private static Map<Integer, String> createMap() {
        Map<Integer, String> result = new HashMap<Integer, String>();
        result.put(1, "one");
        result.put(2, "two");
        return Collections.unmodifiableMap(result);
    }
}
  1. 它避免了匿名课程,我个人认为这是一种不好的风格,并且避免使用
  2. 它使地图的创建更加明确
  3. 它使地图不可修改
  4. 由于MY_MAP是常数,我会将其命名为常量

答案 3 :(得分:167)

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

static final Map<String , String> FLAVORS = new HashMap<String , String>() {{
    put("Up",    "Down");
    put("Charm", "Strange");
    put("Top",   "Bottom");
}};

答案 4 :(得分:90)

第二种方法的一个优点是你可以用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!

答案 5 :(得分:59)

这是一个Java 8单行静态地图初始化器:

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

答案 6 :(得分:48)

在Java 9中:

&#xA;&#xA;
  private static final Map&lt; Integer,String&gt; MY_MAP = Map.of(1,“one”,2,“two”);&#xA;  
&#xA;&#xA;

参见 JEP 269 了解详情。 JDK 9于2017年9月达到了一般可用性

&#xA;

答案 7 :(得分:29)

使用Eclipse Collections,以下所有条件都可以使用:

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 Collections静态初始化原始映射。

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 Collections的提交者

答案 8 :(得分:29)

Java 9

我们可以将Map.ofEntries用作:

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

我们也可以按照Tagir的回答here使用Map.of,但我们使用Map.of的条目不能超过10个。

Java 8(整洁解决方案)

我们可以创建一个地图条目流。我们在Entry中已经有java.util.AbstractMap的两个实现,SimpleEntrySimpleImmutableEntry。对于这个例子,我们可以使用前者:

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

答案 9 :(得分:26)

在这种情况下,我永远不会创建一个匿名子类。如果您想使地图不可修改,静态初始化程序也可以正常工作,例如:

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

答案 10 :(得分:16)

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

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

答案 11 :(得分:16)

查看Google Collections可能很有意思,例如他们在网页上的视频。它们提供了各种方法来初始化地图和集合,并提供不可变集合。

更新:此库现在名为Guava

答案 12 :(得分:11)

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

建议使用unmodifiableMap作为常量,否则它不能被视为常量。

答案 13 :(得分:10)

我强烈建议使用静态块样式的“双括号初始化”样式。

有人可能会评论他们不喜欢匿名课程,开销,表现等等。

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

  1. 元素是嵌套的并且是内联的。
  2. 这是更多的OO,而不是程序性的。
  3. 性能影响非常小,可以忽略不计。
  4. 更好的IDE大纲支持(而不是许多匿名的静态{}阻止)
  5. 你保存了几行评论,以便与他们建立关系。
  6. 防止未初始化对象的可能元素泄漏/实例导致异常和字节码优化器。
  7. 不用担心静态块的执行顺序。
  8. 此外,您了解匿名类的GC,您始终可以使用new HashMap(Map map)将其转换为普通的HashMap。

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

答案 14 :(得分:8)

像往常一样,apache-commons有正确的方法{{3}}:

例如,要创建颜色贴图:

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

答案 15 :(得分:7)

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

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

答案 16 :(得分:7)

当我不想(或不能)使用Guava的ImmutableMap.of(),或者我需要一个可变的Map时,这是我的最爱:

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

答案 17 :(得分:5)

我更喜欢使用静态初始化程序来避免生成匿名类(没有其他目的),因此我将列出使用静态初始化程序初始化的技巧。所有列出的解决方案/提示都是类型安全的。

注意:这个问题没有说明使地图无法修改的问题,所以我将其排除,但要知道可以使用Collections.unmodifiableMap(map)轻松完成。

第一条提示

第一个提示是您可以对地图进行本地引用,并为其指定一个SHORT名称:

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

此处的辅助方法不可重复使用,因为它只能向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
    }
}

答案 18 :(得分:5)

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

话虽如此,只要您知道,这种方法就可以了。我大部分时间用它来以简洁的方式初始化各种系列。

编辑:在评论中正确指出这是一个静态类。显然我没有仔细阅读这篇文章。但是我的评论仍然适用于匿名内部类。

答案 19 :(得分:4)

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

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

答案 20 :(得分:4)

使用Java 8,我开始使用以下模式:

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
  • 之外的任何内容
  • 它的类型安全,可轻松容纳不同类型的键和值。

答案 21 :(得分:4)

您可以使用StickyMap中的MapEntryCactoos

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

答案 22 :(得分:3)

你的第二种方法(Double Brace初始化)被认为是anti pattern,所以我会选择第一种方法。

初始化静态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

答案 23 :(得分:3)

由于Java不支持地图文字,因此必须始终显式地实例化和填充地图实例。

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

例如:

public class LiteralMapFactory {

    // Creates a map from a list of entries
    @SafeVarargs
    public 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 entry
    public 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}

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

答案 24 :(得分:3)

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

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

答案 25 :(得分:3)

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

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

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

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)

(您可以使用&#39;导入静态&#39;以避免需要为方法的名称添加前缀)

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

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

答案 26 :(得分:3)

我不喜欢静态初始化器语法,我不相信匿名子类。一般来说,我同意使用静态初始化程序的所有缺点以及使用在previus答案中提到的匿名子类的所有缺点。另一方面 - 这些帖子中出现的专业人士对我来说还不够。我更喜欢使用静态初始化方法:

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

答案 27 :(得分:2)

我已经阅读了答案,我决定编写自己的地图构建器。随意复制粘贴并享受。

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,使其更适合静态导入。

答案 28 :(得分:2)

嗯......我喜欢枚举;)

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

答案 29 :(得分:0)

注意:该答案实际上属于问题How to directly initialize a HashMap (in a literal way)?,但由于它被标记为与该问题[重复] ...


在Java 9的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> m ) {
    super( m );
}

并添加一个受Aerthel's answer启发但通过使用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:  // key
                if ( keyOrValue == null )
                    throw new IllegalArgumentException( "Key[" + (i >> 1) + "] is <null>." );
                key = (K) keyOrValue;
                continue;
            case 1:  // value
                put( 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: // key
                    if ( keyOrValue == null )
                        throw new IllegalArgumentException( "Key[" + (i >> 1) + "] is <null>." );
                    key = (K) keyOrValue;
                    continue;
                case 1: // value
                    map.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}

答案 30 :(得分:0)

此人使用的是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));

答案 31 :(得分:0)

带有流的Java 8:

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

也可以是将任何内容放入并映射到forEach循环中的Object [] []

答案 32 :(得分:0)

我喜欢使用静态初始化程序&#34;技术&#34;当我有一个抽象类的具体实现,它定义了一个初始化构造函数但没有默认构造函数,但我希望我的子类有一个默认的构造函数。

例如:

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 here
        this(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...
    }
}

答案 33 :(得分:0)

即使使用了Guava非常好的ImmutableMap类,有时候我也想要流利地构建一个可变映射。发现自己想要避免静态阻塞&amp;匿名子类型的东西,当Java 8出现时,我写了一个小的库来帮助调用Fluent

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

使用Java 8接口默认,我可以为所有标准Java Map实现(即HashMap,ConcurrentSkipListMap等)实现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

答案 34 :(得分:0)

以下是AbacusUtil

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

声明:我是AbacusUtil的开发者。

答案 35 :(得分:0)

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

创建自己的静态方法来创建和初始化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);

答案 36 :(得分:0)

在Java 8中,程序方法也可以包含在Supplier

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

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

答案 37 :(得分:0)

现在Java 8已经出局了,这个问题需要重新审视。我对它进行了一次尝试 - 看起来好像你可以利用lambda表达式语法来获得一个非常漂亮和简洁(但类型安全)的地图文字语法,如下所示:

        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 -> 13
                deep -> 21
        );

https://gist.github.com/galdosd/10823529未经测试的示例代码 会对其他人的意见感到好奇(这是一种轻微的邪恶......)

答案 38 :(得分:0)

如果你可以使用数据的字符串表示,这在Java 8中也是一个选项:

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

答案 39 :(得分:0)

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

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

答案 40 :(得分:0)

我喜欢匿名类语法;这只是更少的代码。但是,我发现的一个主要问题是您将无法通过远程处理来序列化该对象。您将获得一个关于无法在远程端找到匿名类的例外。

答案 41 :(得分:0)

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