Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Java, can I declare a HashMap constant?

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!

like image 682
Hoonta Avatar asked May 11 '17 03:05

Hoonta


People also ask

How do you create a constant in HashMap?

The Static Initializer for a Static HashMap We can also initialize the map using the double-brace syntax: Map<String, String> doubleBraceMap = new HashMap<String, String>() {{ put("key1", "value1"); put("key2", "value2"); }};

Can we declare constant in Java?

To turn an ordinary variable into a constant, you have to use the keyword "final." As a rule, we write constants in capital letters to differentiate them from ordinary variables. If you try to change the constant in the program, javac (the Java Compiler) sends an error message.


3 Answers

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);     } } 
like image 106
ZhekaKozlov Avatar answered Oct 21 '22 10:10

ZhekaKozlov


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.

like image 27
GhostCat Avatar answered Oct 21 '22 08:10

GhostCat


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"), …);
like image 40
eckes Avatar answered Oct 21 '22 10:10

eckes