13

I need to create a static Map which maps a given String to an array of int's.

In other words, I'd like to define something like:

"fred" -> {1,2,5,8}
"dave" -> {5,6,8,10,11}
"bart" -> {7,22,10010}
... etc

Is there an easy way to do this in Java?

And if possible, I'd like to use static constants for both the String and the int values.

EDIT: To clarify what I meant by static constants for the values, and to give what I see to be the correct code, here is my first stab at the solution:

public final static String FRED_TEXT = "fred";
public final static String DAVE_TEXT = "dave";

public final static int ONE = 1;
public final static int TWO = 2;
public final static int THREE = 3;
public final static int FOUR = 4;

public final static HashMap<String, int[]> myMap = new HashMap<String, int[]>();
static {
    myMap.put(FRED_TEXT, new int[] {ONE, TWO, FOUR});
    myMap.put(DAVE_TEXT, new int[] {TWO, THREE});
}

Note, these names are not what I'd actually be using. This is just a contrived example.

6 Answers 6

29

You don't need to separate declaration and initialization. If you know how, it can all be done in one line!

// assumes your code declaring the constants ONE, FRED_TEXT etc is before this line
private static final Map<String, int[]> myMap = Collections.unmodifiableMap(
    new HashMap<String, int[]>() {{
        put(FRED_TEXT, new int[] {ONE, TWO, FOUR});
        put(DAVE_TEXT, new int[] {TWO, THREE});
    }});

What we have here is an anonymous class with an initialization block, which is a block of code that executes on construction after constructor, which we've used here to load the map.

This syntax/construct is sometimes erroneously called "double brace initialization" - I suppose because there's two adjacent braces - but there's actually no such thing.

The two cool things about this are:

  • it marries the declaration with the contents, and
  • because the initialization is in-line, you can also make an in-line call to Collections.unmodifiableMap(), resulting in a neat one-line declaration, initialization and conversion to unmodifiable.

If you don't need/want the map to be unmodifiable, leave out that call:

private static final Map<String, int[]> myMap = new HashMap<String, int[]>() {{
    put(FRED_TEXT, new int[] {ONE, TWO, FOUR});
    put(DAVE_TEXT, new int[] {TWO, THREE});
}};
Sign up to request clarification or add additional context in comments.

6 Comments

Ahh, but I need to declare the Map in a super-class, but populate it in a sub-class. Sorry, I know this wasn't in my original question. I would still need the static block in this case?
But since this is static, how can it be "a block of code that executes on construction after constructor"? I thought construction does not occur when you reference static code.
@DuncanKinnear the instance is static, but the block is not. The block is an instance block of the anonymous class that's being instantiated statically. The anonymous class is a subclass of HashMap, of which only one instance will ever exist (new is only called once)
OK, but a quick junit test seems to show that the static block is always run before the constructor, not after. Which makes sense as the result of running the static block should be available to the code executed in the constructor.
@DuncanKinnear firstly, there is no static block. there is only an instance block of a static anonymous class that's a subclass of HashMap that's being initialized statically. the instance block of runs after the HashMap constructor. the whole thing runs before the first use of the containing class (in this case calling the constructor of your class), because the variable is static and all static initialization executes once only before the first use of the class.
|
9

You need to declare and initialize your static map separately.

Here is the declaration piece:

private static final Map<String,int[]> MyMap;

Here is the initialization piece:

static {
    Map<String,int[]> tmpMap = new HashMap<String,int[]>();
    tmpMap.put("fred", new int[] {1,2,5,8});
    tmpMap.put("dave", new int[] {5,6,8,10,11});
    tmpMap.put("bart", new int[] {7,22,10010});
    MyMap = Collections.unmodifiableMap(tmpMap);
}

Unfortunately, arrays are always writable in Java. You wouldn't be able to assign MyMap, but you would be able to add or remove values from other parts of your program that accesses the map.

11 Comments

Of course, the map and the arrays will both be writable in this example.
@cdhowie You are right, I added a paragraph to the answer to emphasize this point.
You could create the map within the static block and wrap it in a unmodifiable map using MyMap = Collections.unmodifiableMap(createdMap);
@DuncanKinnear If you do instantiation inside the static initializer, you can create a temporary map, initialize it, and then wrap it with Collections.unmodifiableMap(temporaryMap) to make the map appear unmodifiable. I edited the answer to show how you can do it.
@Bohemian Nice excuse to downvote a competing answer ;-) I'd like to point out that "need to" and "must" are not the same thing. Moreover, the double-brace alternative hasn't been available before Java 5.
|
6

For the sake of completeness as this is the first result in google for 'java static define map' In Java 8 you can now do this.

Collections.unmodifiableMap(Stream.of(
            new SimpleEntry<>("a", new int[]{1,2,3}),
            new SimpleEntry<>("b", new int[]{1,2,3}),
            new SimpleEntry<>("c", new int[]{1,2,3}))
            .collect(Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue())));

This nice part with this is that we aren't creating anonymous classes anymore with the double brace syntax ({{ }})

We can then extend this with some code to clean up the pattern like this guy did here http://minborgsjavapot.blogspot.ca/2014/12/java-8-initializing-maps-in-smartest-way.html

public static <K, V> Map.Entry<K, V> entry(K key, V value) {
    return new AbstractMap.SimpleEntry<>(key, value);
}

public static <K, U> Collector<Map.Entry<K, U>, ?, Map<K, U>> entriesToMap() {
    return Collectors.toMap((e) -> e.getKey(), (e) -> e.getValue());
}

public static <K, U> Collector<Map.Entry<K, U>, ?, ConcurrentMap<K, U>> entriesToConcurrentMap() {
    return Collectors.toConcurrentMap((e) -> e.getKey(), (e) -> e.getValue());
}

final result

Collections.unmodifiableMap(Stream.of(
            entry("a", new int[]{1,2,3}),
            entry("b", new int[]{1,2,3}),
            entry("c", new int[]{1,2,3}))
            .collect(entriesToMap()));

which would give us a Concurrent Unmodifiable Map.

1 Comment

Thanks for the answer. Shame we're stuck on Java 6.
1
static Map<String, int[]> map = new HashMap<>();

The map is static, you can access it without creating an instance of the class it's defined in. I don't know what you mean with having the keys and values static as well, because it makes no sense to me.

1 Comment

Please see my edit for an example of using the static constants.
0
public class ExampleClass {
    public final static HashMap consts = new HashMap();
    static
    {
        constants.put("A", "The Letter A");
        constants.put("B", "The Letter B");
        constants.put("C", "The Letter C");
    }
    /* Rest of your class that needs to know the consts */
}

2 Comments

Correct me if i am wrong but static block is executed before the "consts" initialization right ?
I have tested and whatever you have written is correct. But if we switch the consts intitialization block and the static block, it will throw compilation error. I never thought the order of defining the elements would have any effect in Java.
0

You can also use: ImmutableMap.of(key, val)

https://guava.dev/releases/23.0/api/docs/com/google/common/collect/ImmutableMap.html#of--

1 Comment

Thanks for trying to help. Your answer would be more useful if you added more details on how to use it rather than just the javadoc link?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.