1198

你将如何Map在 Java 中初始化一个静态变量?

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

各自的优缺点是什么?

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

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

43 回答 43

1169

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

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

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);
    }
}
于 2009-02-03T15:51:04.420 回答
468

我喜欢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 的不可变集合实用程序的好处,请参阅Guava 用户指南中解释的不可变集合。

Guava 的(一个子集)曾经被称为Google Collections。如果您还没有在 Java 项目中使用这个库,我强烈建议您尝试一下!正如其他 SO 用户所同意的那样,Guava 已迅速成为 Java 最流行和最有用的免费 3rd 方库之一。(如果您是新手,该链接后面有一些优秀的学习资源。)


更新(2015 年):至于Java 8,好吧,我仍然会使用 Guava 方法,因为它比其他任何方法都干净。如果您不想要 Guava 依赖,请考虑使用普通的旧 init 方法如果你问我,二维数组和 Stream API的 hack非常丑陋,如果你需要创建一个键和值不是同一类型的 Map(就像Map<Integer, String>问题中一样),它会变得更丑陋。

至于 Guava 的未来,关于 Java 8,Louis Wasserman早在 2014 年就说过,2016 年 [更新] 宣布Guava 21 将需要并正确支持 Java 8


更新(2016 年):正如Tagir Valeev 指出的那样Java 9最终将通过为集合添加便利工厂方法,只使用纯 JDK 来实现这一点:

static final Map<Integer, String> MY_MAP = Map.of(
    1, "one", 
    2, "two"
);
于 2011-08-31T13:58:37.283 回答
197

我会使用:

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. 它使地图的创建更加明确
  3. 它使地图不可修改
  4. 由于 MY_MAP 是常量,我将其命名为常量
于 2009-02-03T21:40:14.573 回答
188

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

static final Map<String , String> FLAVORS = new HashMap<String , String>() {{
    put("Up",    "Down");
    put("Charm", "Strange");
    put("Top",   "Bottom");
}};
于 2009-07-15T21:29:54.440 回答
102

第二种方法的一个优点是您可以将其包装起来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!
于 2009-02-03T15:44:58.300 回答
70

Map.of在 Java 9+

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

有关详细信息,请参阅JEP 269。JDK 9于 2017 年 9 月全面上市

于 2015-12-29T10:07:24.950 回答
63

这是一个 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]));

编辑:要在问题中初始化 a 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

于 2014-09-14T00:44:37.927 回答
53

爪哇 9

我们可以使用Map.ofEntries, 调用Map.entry( k , v )来创建每个条目。

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.

爪哇 8

我们可以创建一个映射条目流。我们已经有两个实现Entryjava.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));
            
于 2016-05-23T07:17:08.880 回答
31

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

于 2012-12-18T23:10:43.323 回答
29

在这种情况下,我永远不会创建匿名子类。如果您想让地图不可修改,静态初始化器同样可以工作,例如:

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);
}
于 2009-02-03T15:55:18.810 回答
18

看看Google Collections可能会很有趣,例如他们页面上的视频。它们提供了各种初始化地图和集合的方法,并且还提供了不可变集合。

更新:这个库现在被命名为Guava

于 2009-02-03T21:33:02.823 回答
17

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

public static final Map<?, ?> numbers = Collections.unmodifiableMap(new HashMap<Integer, String>() {
    {
        put(1, "some value");
                    //rest of code here
    }
});
于 2013-09-19T08:48:59.010 回答
12
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 用于常量,否则它不能被视为常量。

于 2010-06-03T08:18:48.417 回答
10

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

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

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

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

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

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

于 2010-12-12T04:29:03.437 回答
9

像往常一样 apache-commons 有适当的方法MapUtils.putAll(Map, Object[])

例如,要创建一个颜色图:

Map<String, String> colorMap = MapUtils.putAll(new HashMap<String, String>(), new String[][] {
     {"RED", "#FF0000"},
     {"GREEN", "#00FF00"},
     {"BLUE", "#0000FF"}
 });
于 2015-09-08T09:32:09.580 回答
8

这是我最喜欢的,如果我

  • 不想(或不能)使用 Guava 的ImmutableMap.of()
  • 或者我需要一个可变的Map
  • 或者我需要超过Map.of()JDK9+的 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));
于 2016-09-15T12:09:43.897 回答
7

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

注意:这个问题并没有说明关于使地图不可修改的任何内容,所以我将把它省略,但知道它可以很容易地用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);
}

此处的辅助方法不可重用,因为它只能将元素添加到myMap2. 为了使其可重用,我们可以将映射本身作为辅助方法的参数,但初始化代码不会更短。

第三个提示

第三个技巧是您可以创建一个可重用的类似构建器的辅助类,并具有填充功能。这实际上是一个简单的 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
    }
}
于 2014-04-22T08:46:50.750 回答
7

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

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

于 2017-11-26T03:38:36.390 回答
5

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

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

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

于 2009-02-03T16:31:26.677 回答
5

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

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);
        }
    }
}
于 2013-08-02T01:30:58.623 回答
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
  • 它是类型安全的,并且很容易适应不同类型的键和值。
于 2015-11-20T00:26:24.170 回答
4

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

Map<K, V> map = Collections.singletonMap(key, value)
于 2017-04-30T21:28:08.007 回答
4

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

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

于 2017-05-23T09:29:22.520 回答
4

您可以使用StickyMapand MapEntryfrom Cactoos

private static final Map<String, String> MAP = new StickyMap<>(
  new MapEntry<>("name", "Jeffrey"),
  new MapEntry<>("age", "35")
);
于 2017-06-20T17:28:06.330 回答
3

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

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;
    }
}
于 2012-08-27T06:09:31.830 回答
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)

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

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

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

于 2015-06-03T20:46:29.060 回答
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}

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

于 2016-02-26T21:53:35.680 回答
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,使其更适合静态导入。

于 2015-05-20T09:13:47.693 回答
2

JEP 269为 Collections API 提供了一些便利的工厂方法。该工厂方法不在当前的 Java 版本中,即 8,但计划在 Java 9 版本中发布。

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

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 Early Access试用这些功能。

于 2016-04-10T15:08:52.067 回答
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 ) );
}
于 2017-10-25T16:28:13.200 回答
1

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

例如:

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...
    }
}
于 2015-01-28T21:35:25.137 回答
1

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


在 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> 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:  // 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}
于 2018-09-10T23:59:34.177 回答
1

这个使用 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));
于 2019-06-25T08:39:48.030 回答
0

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

于 2009-02-03T15:45:34.260 回答
0

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

于 2009-02-03T16:18:07.047 回答
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;
}
于 2009-02-03T18:40:56.433 回答
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]));
于 2014-01-13T04:39:14.663 回答
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上未经测试的示例代码 会很好奇其他人对此的看法(这有点邪恶......)

于 2014-04-16T07:32:03.843 回答
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();

这只是假设的方式,但如果您真的需要单线,它可以派上用场。

于 2015-08-06T16:10:30.540 回答
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);
于 2016-01-28T16:20:21.027 回答
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的开发者。

于 2016-11-28T23:17:00.143 回答
0

即使使用 Guava 不错的 ImmutableMap 类,有时我也想流畅地构建可变映射。发现自己想要避免静态块和匿名子类型的事情,当 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

于 2016-11-30T01:16:09.423 回答
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])));
    }

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

于 2020-11-19T13:52:16.997 回答