关于Java:如何初始化静态映射Map?

How can I initialise a static Map?

如何在Java中初始化静态EDCOX1 0?

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

每种方法的优缺点是什么?

下面是两种方法的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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");
        }
    };
}


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

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

1
2
3
4
5
6
7
8
9
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);
    }
}


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

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

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

如果您希望地图有5个以上的条目,则不能再使用ImmutableMap.of()。相反,沿着这些线尝试ImmutableMap.builder()

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

要了解更多关于guava不可变收集实用程序的好处,请参阅guava用户指南中介绍的不可变收集。

(guava的一个子集)过去被称为google collections。如果您还没有在Java项目中使用这个库,我强烈建议试用它!GuAVA迅速成为Java最流行和最有用的免费第三方LIBS之一,用户同意。(如果您对它还不熟悉,那么在这个链接后面有一些优秀的学习资源。)

更新(2015):至于Java 8,嗯,我还是会使用番石榴的方法,因为它比其他任何东西都干净。如果您不希望guava依赖,可以考虑使用一个普通的旧init方法。如果你问我的话,使用二维数组和流API的黑客是相当难看的,如果你需要创建一个键和值不是同一类型的映射(如问题中的Map),它会变得更难看。

至于一般的番石榴的未来,关于Java 8,Louis Wasserman在2014说了这一点,并且[更新]在2016中宣布,番石榴21将需要并适当地支持Java 8。

更新(2016):正如Tagir Valeev所指出的,Java 9将通过使用便利的工厂方法为集合而使用纯JDK来最终做到这一点:

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


I would use:

1
2
3
4
5
6
7
8
9
10
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);
    }
}
  • 它避免匿名类,我个人认为这是一种糟糕的风格,并避免
  • 它使地图的创建更加明确
  • 它使地图不可修改
  • 因为我的地图是常量,所以我将它命名为常量

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

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


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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!


    这里有一个Java 8单线静态地图初始化器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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,您需要这样做:

    1
    2
    3
    static final Map<Integer, String> MY_MAP = Arrays.stream(new Object[][]{
            {1,"one
    <div class="
    suo-content">[collapse title=""]<ul><li>我冒昧地添加了一个与问题和其他答案相同的版本:初始化一个键和值类型不同的映射(所以<wyn>String[][]</wyn>不会这样做,需要<wyn>Object[][]</wyn>)。imho,这种方法很难看(对演员来说更是如此),很难记住;我自己也不会用。</li><li>用于初始化Java 8中的映射:StaskOfFult.COM/A/338 473/1216775</li></ul>[/collapse]</div><hr><P>在Java 9中:</P>[cc lang="java"]private static final Map<Integer, String> MY_MAP = Map.of(1,"one", 2,"two");

    详情见jep 269。JDK9于2017年9月正式上市。


    爪哇9

    我们可以使用Map.ofEntries作为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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在回答中的建议使用Map.of,但使用Map.of的条目不能超过10个。

    Java 8(整洁解决方案)

    我们可以创建一个地图条目流。我们已经在java.util.AbstractMap中实现了两个Entry,分别是simpleEntry和simpleImmutableEntry。对于这个例子,我们可以使用前者作为:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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));


    对于Eclipse集合,以下所有内容都可以工作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    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集合静态初始化原语映射。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    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集合的提交者


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

    1
    2
    3
    4
    5
    6
    7
    8
    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);
    }


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

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

    Maybe it's interesting to check out Google Collections, e.g. the videos that they have on their page. They provide various ways to initialize maps and sets, and provide immutable collections as well.

    Update: This library is now named Guava.


    1
    2
    3
    4
    5
    6
    7
    8
    9
    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
    2
    3
    4
    5
    6
    7
    8
    9
    public class Test {

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

    建议对常数使用不可修改映射,否则不能将其视为常数。


    我可以强烈建议使用"双括号初始化"样式而不是静态块样式。

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

    但我更考虑的是代码的可读性和可维护性。在这一点上,我认为双括号是比静态方法更好的代码样式。

  • 元素是嵌套和内联的。
  • 它更像是OO,而不是程序性的。
  • 性能影响非常小,可以忽略不计。
  • 更好的IDE大纲支持(而不是许多匿名静态块)
  • 你只保存了几行评论,就为他们带来了关系。
  • 防止未初始化对象的元素泄漏/实例线索出现异常和字节码优化器。
  • 不用担心静态块的执行顺序。
  • 此外,如果您知道匿名类的GC,则可以使用new HashMap(Map map)将其转换为普通散列映射。

    你可以这样做,直到你面临另一个问题。如果这样做,您应该为它使用完整的另一种编码样式(例如,没有静态的,工厂类)。


    与往常一样,ApacheCommons具有正确的方法maputils.putall(map,object[]):

    例如,要创建颜色映射:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    Map<String, String> colorMap = MapUtils.putAll(new HashMap<String, String>(), new String[][] {
         {"RED","#FF0000
    <div class="
    suo-content">[collapse title=""]<ul><li>我在所有的构建中都包含了Apache CAMONS,因此,在一个简单的Java中缺少一个方法EDCOX1(2)的情况下,我认为这是最好的解决方案。重新发明轮子通常是愚蠢的。非常小的缺点是,对于泛型,它需要不受检查的转换。</li><li>@MikCorrunt 4.1版本是通用的:public static<k,v>map<k,v>putall(final map<k,v>map,final object[]array)</li><li>TX…是的,我用的是4.1,但在Eclipse中,我仍然需要使用像<wyn>Map<String, String> dummy = MapUtils.putAll(new HashMap<String, String>(), new Object[][]... )</wyn>这样的行来处理<wyn>SuppressWarnings( unchecked )</wyn>。</li><li>@是因为物体的缘故吗?看到更新的未磨损-我在Eclipse中没有任何警告。</li><li>多么奇怪…即使我走了,我也会得到"警告"!当然,只有当你的<wyn>K</wyn>和<wyn>V</wyn>是同一类时,这才有效。我认为你没有(可以理解)在Eclipse设置中将"unchecked conversion"设置为"ignore"?</li><li>@MikCorrunt我没有注释,"unchecked generic type operation"设置为"warning"。从hashmap中删除类型会导致出现警告。</li><li>我的日食是火星2号4.5.2版本。或者是Java版本的差异?我使用1.8.0_91作为EclipseJRE。否则我就放弃:神秘!</li><li>@MikCordent I有Neon版本(4.6.0)和JDK1.8.0 U 74</li></ul>[/collapse]</div><hr><P>如果你想要不可修改的地图,最后Java 9向EDCOX1×0接口添加了一个很酷的工厂方法EDCOX1×1。类似的方法也被添加到set和list中。</P><P><wyn>Map<String, String> unmodifiableMap = Map.of("key1","value1","key2","value2");</wyn></P><hr><P>如果我不想(或不能)使用番石榴的<wyn>ImmutableMap.of()</wyn>,或者如果我需要一个可变的<wyn>Map</wyn>,这是我的最爱:</P>[cc lang="java"]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]);
            }
        }};
    }

    它非常紧凑,并且忽略了杂散值(即没有值的最后一个键)。

    用途:

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

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

    注:这个问题并没有说明如何使地图不可修改,所以我将不提这个问题,但我知道使用Collections.unmodifiableMap(map)可以很容易地完成。

    第一小费

    第一个提示是,您可以对地图进行本地引用,并为其提供一个简短的名称:

    1
    2
    3
    4
    5
    6
    7
    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");
    }

    第二小费

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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添加元素。为了使其可重用,我们可以将映射本身设置为helper方法的参数,但初始化代码不会缩短。

    第三尖

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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
        }
    }

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

    说了这句话,只要你知道,这种方法就可以了。大多数时候我都用它以简洁的方式初始化各种集合。

    编辑:在注释中正确指出这是一个静态类。显然,我读得不够仔细。不过,我的评论仍然适用于匿名内部类。


    您可以使用Cactoos的StickyMapMapEntry

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

    如果您想要一些简洁和相对安全的东西,您可以将编译时类型检查转换为运行时:

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

    此实现应捕获任何错误:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    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);
            }
        }
    }

    With Java 8 I've come to use the following pattern:

    1
    2
    3
    4
    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以外的任何东西。
    • 它是类型安全的,很容易适应不同类型的键和值。


    因为Java不支持地图文字,所以地图实例必须始终显式实例化并填充。

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

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    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}

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


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

    我不喜欢使用静态初始值设定项,因为它们笨重,我不喜欢匿名类,因为它正在为每个实例创建一个新类。

    相反,我更喜欢这样的初始化:

    1
    2
    3
    4
    5
    map(
        entry("keyA","val1"),
        entry("keyB","val2"),
        entry("keyC","val3")
    );

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

    1
    2
     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)

    (可以使用"import static"避免在方法名称前面加前缀)

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

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


    第二种方法(双括号初始化)被认为是反模式的,所以我将使用第一种方法。

    初始化静态映射的另一个简单方法是使用此实用程序函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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。


    我不喜欢静态初始值设定项语法,也不相信匿名子类。一般来说,我同意使用静态初始值设定项的所有缺点,以及使用previus答案中提到的匿名子类的所有缺点。另一方面,这些职位上的专业人士对我来说还不够。我更喜欢使用静态初始化方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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;
        }
    }

    好。。。我喜欢菊花;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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 ) );
    }

    如果只需要向映射中添加一个值,则可以使用collections.singletonmap:

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

    jep 269为集合API提供了一些便利的工厂方法。此工厂方法不在当前Java版本中,这是8,但计划用于Java 9版本。

    对于Map有两种出厂方法:ofofEntries。使用of可以传递交替的键/值对。例如,为了创建一个类似于{age: 27, major: cs}Map

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

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

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

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


    我读过答案,决定自己写地图建设者。随意复制粘贴并享受。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    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,使之更适合静态进口。


    注意:这个答案实际上属于问题:如何直接初始化哈希映射(以文字方式)?但既然它被标为这个的[副本]…

    在Java 9及其map .Of()之前(也限制于10个映射),您可以扩展您选择的EDCOX1×0实现,例如:

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

    重新实施HashMap的施工人员:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    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 );
    }

    并添加一个额外的构造器,其灵感来自于Aertel的答案,但使用Object...类型是通用的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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 );
            }
    }

    1
    2
    3
    4
    5
    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
    {1=First, 2=Second, 3=Third}

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    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;
        }
    }

    1
    2
    3
    4
    public static void main( final String[] args ) {

        System.out.println( InitMap.of( 1,"First", 2,"Second", 3,"Third" ) );
    }

    产量

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

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

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

    这是我的newMap方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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;
        }
    }

    用途:

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

    它不使用泛型,但您可以根据自己的需要对地图进行类型转换(只需确保您正确地对其进行了类型转换!)

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

    I like using the static initializer"technique" when I have a concrete realization of an abstract class that has defined an initializing constructor but no default constructor but I want my subclass to have a default constructor.

    For example:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    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;
        }
    }

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    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);
        }
    }

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class StaticInitDemo {

        public static void main(String[] args) {

            // create a translucent, yellow square...
            Shape defaultSquare = new SquareShapeImpl();

            // etc...
        }
    }

    即使有了番石榴的好的不变的地图类,有时我还是想流畅地构建一个可变的地图。发现自己想要避免静态块和匿名子类型的东西,当Java 8出现时,我编写了一个小型库来帮助调用FLUENT。

    1
    2
    3
    4
    5
    // 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接口缺省,我可以实现FLUENT .MAP方法,用于所有标准的Java MAP实现(ie HashMap,CONCURENCE SKIPLISTMAP,…等)没有冗长的重复。

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

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

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


    在Java 8中,程序方法也可以被封装在EDCOX1,4中:

    1
    2
    3
    4
    5
    6
    Map<String,String> m = ((Supplier<Map<String,String>>)(() -> {
        Map<String,String> result = new HashMap<>();
        result.put("foo","hoo");
        ...
        return result;
    )).get();

    这只是一种假设的方法,但如果你真的需要一条航线的话,它可以派上用场。


    我做了一些不同的事情。不是最好的,但对我有用。也许它可以被"遗传"。

    1
    2
    3
    4
    5
    6
    7
    private static final Object[][] ENTRIES =
    {
      {new Integer(1),"one
    <div class="
    suo-content">[collapse title=""]<ul><li>我喜欢用这种方式初始化映射所需的小代码</li><li>这种方法的问题在于它根本不是类型安全的(如果您使用Java,则需要类型安全)。可以将任何类型的对象作为键和值。它只适用于<wyn>Map<Object, Object></wyn>(尽管人们可以使用与<wyn>String[][]</wyn>相似的方法来处理<wyn>Map<String,String></wyn>,与其他<wyn>Map<T,T></wyn>相似。它不适用于键类型不同于值类型的映射。</li></ul>[/collapse]</div><hr><P>如果您可以使用数据的字符串表示形式,那么在Java 8中也是这样的选择:</P>[cc lang="java"]static Map<Integer, String> MAP = Stream.of(
           "
    1=one",
           "
    2=two"
    ).collect(Collectors.toMap(k -> Integer.parseInt(k.split("
    =")[0]), v -> v.split("=")[1]));

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


    现在Java 8不在了,这个问题值得重新考虑。我尝试了一下——看起来您可以利用lambda表达式语法来获得一个非常好和简洁(但类型安全)的map文本语法,如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
            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上的未测试样本代码会好奇别人对这件事的看法(这有点邪恶…)


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


    这是AbacusUtil的代码

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

    声明:我是AbacusUtil的开发者。