In Java, can I declare a HashMap constant?
Solution 1
There are two aspects here:
- You have a variable that holds a reference to a map. You simply declare that variable to be final; and voilà, you can't change the variable to point to another reference.
- But that doesn't prevent you from changing the state of the object that reference is pointing. So even when you have a final Map object, you could still call put/remove/... methods on that Map.
So, in order to come to a real "constant" Map, you do go for this:
First you create an ordinary map containing all the desired values.
Then you use Collections.unmodifiableMap()
in order to create a map that can't be changed any more.
The one thing to pay attention to: you have to make sure that you are not leaking a reference to the original map object as that immutable map is just a wrapper around that initial map. You could do that in a little helper method for example.
If you are asking: is there a way to write down a map declaration in a special "literal form" (like for arrays) - there isn't. Well, you can change that helper method to take Object ...
as parameter; and then you would go through those parameters, one is a number, next one a string, and use that to fill the map. So you could then invoke the method with a single sequence of values. But probably not worth the effort ...
A quick update: Java9 added various static helper methods that allow you write down maps in a somehow "literal" way, see here for example.
Solution 2
Yes, it can be a constant. You should declare your HashMap
instance as follows:
class <class name> {
private static final HashMap<Integer, String> tensNumberConversion = new HashMap<>();
static {
tensNumberConversion.put(2, "twenty");
tensNumberConversion.put(3, "thirty");
tensNumberConversion.put(4, "forty");
tensNumberConversion.put(5, "fifty");
tensNumberConversion.put(6, "sixty");
tensNumberConversion.put(7, "seventy");
tensNumberConversion.put(8, "eighty");
tensNumberConversion.put(9, "ninety");
}
}
However, this is only a constant reference. While you can not reassign tensNumberConversion
to something else, you still can change the contents of your map later at runtime:
tensNumberConversion = new HashMap<>(); // won't compile
tensNumberConversion.put(9, "one"); // succeeds
If you want the contents of your map constant too, you should wrap the HashMap
into an unmodifiable map:
class <class name> {
private static final Map<Integer, String> tensNumberConversion = initMap();
private static Map<Integer, String> initMap() {
Map<Integer, String> map = new HashMap<>();
map.put(2, "twenty");
map.put(3, "thirty");
map.put(4, "forty");
map.put(5, "fifty");
map.put(6, "sixty");
map.put(7, "seventy");
map.put(8, "eighty");
map.put(9, "ninety");
return Collections.unmodifiableMap(map);
}
}
Solution 3
Just a BTW, with Java 9 there are static methods in the Map
interface to create immutable Maps with some number of entries like:
Map<String,String> m = Map.of("k1", "v1",
"K2", "v2");
Or if more than 10 entries are needed:
import static java.util.Map.entry;
Map<String, String> m = Map.ofEntries(
entry("k1", "v1"), entry("k2", "v2"), …);
Solution 4
I somehow missed the easiest form for direct initialization of the HashMap here
private static final Map<Integer, String> tensNumberConversion_internal = new HashMap<Integer, String>()
{
{
put(2, "twenty");
put(3, "thirty");
put(4, "forty");
put(5, "fifty");
put(6, "sixty");
put(7, "seventy");
put(8, "eighty");
put(9, "ninety");
};
};
and as for making it unchangeable you already have Collections.unmodifiableMap
from the accepted answer so do
public static final Map<Integer, String> tensNumberConversion = Collections.unmodifiableMap(tensNumberConversion_internal);
they have to be created in this order ofcourse ;)
Related videos on Youtube
Hoonta
Updated on July 09, 2022Comments
-
Hoonta almost 2 years
I am writing a simple program to convert a number to a word representing that number (13 => "thirteen").
I realize I could get some of the words with a constant String array like this:
private static final String[] tensNames = {"", " ten", " twenty", " thirty", " forty", " fifty", " sixty", " seventy", " eighty", " ninety" };
...and access it with the index, but I wanted to try it with a HashMap like this:
final HashMap<Integer, String> tensNumberConversion = new HashMap<Integer, String>(); tensNumberConversion.put(2, "twenty"); tensNumberConversion.put(3, "thirty"); tensNumberConversion.put(4, "forty"); tensNumberConversion.put(5, "fifty"); tensNumberConversion.put(6, "sixty"); tensNumberConversion.put(7, "seventy"); tensNumberConversion.put(8, "eighty"); tensNumberConversion.put(9, "ninety");
I was instructed by a teacher to make these constants. Can the HashMap be a constant? As a newbie, it wasn't totally clear how the terms "constant" and "static" and "final" are related, and what exactly makes a constant. (static alone? final alone? static final together?).
I tried making it private static final Hashmap but IntelliJ gave me an error (modifier 'private' not allowed here...same for 'static').
However, it does compile from my terminal with no errors. If a HashMap can be a constant, is this the right way to declare one? Thanks!
-
Courage about 7 yearsIt can be a constant, where are you declaring your
HashMap
? -
ZhekaKozlov about 7 yearsPossible duplicate of How can I initialise a static Map?
-
Hoonta almost 7 yearsAccording to what I see, I accepted your answer on May 12th. Is that different from what you see?
-
-
ZhekaKozlov about 7 yearsCollections.unmodifiableMap
-
GhostCat about 7 yearsMuch better now.
-
Hulk about 7 yearsbut that is basically what the map returned by
Collections.unmodifiableMap
already does - except that it throws instead of pretending to work - all modifying methods throw UnsupportedOperationException. -
hansvb over 5 yearsI would not call that the "simplest" form, the double-brace initialization trick is quite a heavy hack: stackoverflow.com/questions/924285/…
-
nar-007 almost 4 yearsAnyway, map.of or map.ofEntry will maintain order?
-
Prashant almost 4 yearsI think it's only guaranteed for SortedMap implementations and LinkedHashMap. Map.of specifically mentions that the iteration order is unspecified. docs.oracle.com/javase/9/docs/api/java/util/Map.html#immutable