How can I initialise a static Map?

前端 未结 30 1039
慢半拍i
慢半拍i 2020-11-22 08:43

How would you initialise a static Map in Java?

Method one: static initialiser
Method two: instance initialiser (anonymous subclass) or some other m

相关标签:
30条回答
  • 2020-11-22 09:37

    I could strongly suggest the "double brace initialization" style over static block style.

    Someone may comment that they don't like anonymous class, overhead, performance, etc.

    But that I more consider is the code readability and maintainability. In this point of view, I stand a double brace is a better code style rather then static method.

    1. The elements are nested and inline.
    2. It is more OO, not procedural.
    3. the performance impact is really small and could be ignored.
    4. Better IDE outline support (rather then many anonymous static{} block)
    5. You saved few lines of comment to bring them relationship.
    6. Prevent possible element leak/instance lead of uninitialized object from exception and bytecode optimizer.
    7. No worry about the order of execution of static block.

    In addition, it you aware the GC of the anonymous class, you can always convert it to a normal HashMap by using new HashMap(Map map).

    You can do this until you faced another problem. If you do, you should use complete another coding style (e.g. no static, factory class) for it.

    0 讨论(0)
  • 2020-11-22 09:39

    Here's a Java 8 one-line static map initializer:

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

    Edit: to initialize a Map<Integer, String> as in the question, you'd need something like this:

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

    Edit(2): There is a better, mixed-type-capable version by i_am_zero that uses a stream of new SimpleEntry<>(k, v) calls. Check out that answer: https://stackoverflow.com/a/37384773/3950982

    0 讨论(0)
  • 2020-11-22 09:39

    If you only need to add one value to the map you can use Collections.singletonMap:

    Map<K, V> map = Collections.singletonMap(key, value)
    
    0 讨论(0)
  • 2020-11-22 09:41

    Here's my favorite when I don't want to (or cannot) use Guava's ImmutableMap.of(), or if I need a mutable 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]);
            }
        }};
    }
    

    It's very compact, and it ignores stray values (i.e. a final key without a value).

    Usage:

    Map<String, String> one = asMap("1stKey", "1stVal", "2ndKey", "2ndVal");
    Map<String, Object> two = asMap("1stKey", Boolean.TRUE, "2ndKey", new Integer(2));
    
    0 讨论(0)
  • 2020-11-22 09:42

    I have not seen the approach I use (and have grown to like) posted in any answers, so here it is:

    I don't like using static initializers because they are clunky, and I don't like anonymous classes because it is creating a new class for each instance.

    instead, I prefer initialization that looks like this:

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

    unfortunately, these methods are not part of the standard Java library, so you will need to create (or use) a utility library that defines the following methods:

     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)
    

    (you can use 'import static' to avoid needing to prefix the method's name)

    I found it useful to provide similar static methods for the other collections (list, set, sortedSet, sortedMap, etc.)

    Its not quite as nice as json object initialization, but it's a step in that direction, as far as readability is concerned.

    0 讨论(0)
  • 2020-11-22 09:43

    Java 9

    We can use Map.ofEntries, calling Map.entry( k , v ) to create each entry.

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

    We can also use Map.of as suggested by Tagir in his answer here but we cannot have more than 10 entries using Map.of.

    Java 8 (Neat Solution)

    We can create a Stream of map entries. We already have two implementations of Entry in java.util.AbstractMap which are SimpleEntry and SimpleImmutableEntry. For this example we can make use of former as:

    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));
    
    0 讨论(0)
提交回复
热议问题