Correct way to initialize HashMap and can HashMap hold different value types?

JavaStandardsHashmap

Java Problem Overview


So I have two questions about HashMaps in Java:

  1. What is the correct way to initialize a HashMap? I think it might be best in my situation to use:

    HashMap x = new HashMap();

But Eclipse keeps suggesting that I use:

    HashMap<something, something> map = new HashMap();

Which is better?

  1. Can a HashMap hold different types of objects/data types as values? For example, would this work and be OK:

    map.put("one", 1); map.put("two", {1, 2}); map.put("three", "hello");

In the first put(), I want an int as a value, in the second an int[], and third a string. Is this okay to do in Java with HashMaps? Also, is it okay to store a HashMap as a value within a HashMap?

Java Solutions


Solution 1 - Java

It really depends on what kind of type safety you need. The non-generic way of doing it is best done as:

 Map x = new HashMap();

Note that x is typed as a Map. this makes it much easier to change implementations (to a TreeMap or a LinkedHashMap) in the future.

You can use generics to ensure a certain level of type safety:

Map<String, Object> x = new HashMap<String, Object>();

In Java 7 and later you can do

Map<String, Object> x = new HashMap<>();

The above, while more verbose, avoids compiler warnings. In this case the content of the HashMap can be any Object, so that can be Integer, int[], etc. which is what you are doing.

If you are still using Java 6, Guava Libraries (although it is easy enough to do yourself) has a method called newHashMap() which avoids the need to duplicate the generic typing information when you do a new. It infers the type from the variable declaration (this is a Java feature not available on constructors prior to Java 7).

By the way, when you add an int or other primitive, Java is autoboxing it. That means that the code is equivalent to:

 x.put("one", Integer.valueOf(1));

You can certainly put a HashMap as a value in another HashMap, but I think there are issues if you do it recursively (that is put the HashMap as a value in itself).

Solution 2 - Java

This is a change made with Java 1.5. What you list first is the old way, the second is the new way.

By using HashMap you can do things like:

HashMap<String, Doohickey> ourMap = new HashMap<String, Doohickey>();

....

Doohickey result = ourMap.get("bob");

If you didn't have the types on the map, you'd have to do this:

Doohickey result = (Doohickey) ourMap.get("bob");

It's really very useful. It helps you catch bugs and avoid writing all sorts of extra casts. It was one of my favorite features of 1.5 (and newer).

You can still put multiple things in the map, just specify it as Map, then you can put any object in (a String, another Map, and Integer, and three MyObjects if you are so inclined).

Solution 3 - Java

Eclipse is recommending that you declare the type of the HashMap because that enforces some type safety. Of course, it sounds like you're trying to avoid type safety from your second part.

If you want to do the latter, try declaring map as HashMap<String,Object>.

Solution 4 - Java

The way you're writing it is equivalent to

HashMap<Object, Object> map = new HashMap<Object, Object>();

What goes inside the brackets is you communicating to the compiler what you're going to put in the HashMap so that it can do error checking for you. If Object, Object is what you actually want (probably not) you should explicitly declare it. In general you should be as explicit as you can with the declaration to facilitate error checking by the compiler. What you've described should probably be declared like this:

HashMap<String, Object> map = new HashMap<String, Object>();

That way you at least declare that your keys are going to be strings, but your values can be anything. Just remember to use a cast when you get a value back out.

Solution 5 - Java

The 2nd one is using generics which came in with Java 1.5. It will reduce the number of casts in your code & can help you catch errors at compiletime instead of runtime. That said, it depends on what you are coding. A quick & dirty map to hold a few objects of various types doesn't need generics. But if the map is holding objects all descending from a type other than Object, it can be worth it.

The prior poster is incorrect about the array in a map. An array is actually an object, so it is a valid value.

Map<String,Object> map = new HashMap<String,Object>();
map.put("one",1); // autoboxed to an object
map.put("two", new int[]{1,2} ); // array of ints is an object
map.put("three","hello"); // string is an object

Also, since HashMap is an object, it can also be a value in a HashMap.

Solution 6 - Java

A HashMap can hold any object as a value, even if it is another HashMap. Eclipse is suggesting that you declare the types because that is the recommended practice for Collections. under Java 5. You are free to ignore Eclipse's suggestions.

Under Java 5, an int (or any primitive type) will be autoboxed into an Integer (or other corresponding type) when you add it to a collection. Be careful with this though, as there are some catches to using autoboxing.

Solution 7 - Java

Eclipse is suggesting you to define generic type so that you can have type safety. You can write

Map m = new HashMap();

which does not ensure type safety but following will ensure type safety

Map<Object,Object> = new HashMap<Object,Object>();

The Object can be any type such as String, Integer etc.

Solution 8 - Java

Map.of literals

As of Java 9, there is yet another way to instantiate a Map. You can create an unmodifiable map from zero, one, or several pairs of objects in a single-line of code. This is quite convenient in many situations.

For an empty Map that cannot be modified, call Map.of(). Why would you want an empty set that cannot be changed? One common case is to avoid returning a NULL where you have no valid content.

For a single key-value pair, call Map.of( myKey , myValue ). For example, Map.of( "favorite_color" , "purple" ).

For multiple key-value pairs, use a series of key-value pairs. ``Map.of( "favorite_foreground_color" , "purple" , "favorite_background_color" , "cream" )`.

If those pairs are difficult to read, you may want to use Map.of and pass Map.Entry objects.

Note that we get back an object of the Map interface. We do not know the underlying concrete class used to make our object. Indeed, the Java team is free to used different concrete classes for different data, or to vary the class in future releases of Java.

The rules discussed in other Answers still apply here, with regard to type-safety. You declare your intended types, and your passed objects must comply. If you want values of various types, use Object.

Map< String , Color > preferences = Map.of( "favorite_color" , Color.BLUE ) ;

Solution 9 - Java

In answer to your second question: Yes a HashMap can hold different types of objects. Whether that's a good idea or not depends on the problem you're trying to solve.

That said, your example won't work. The int value is not an Object. You have to use the Integer wrapper class to store an int value in a HashMap

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTony StarkView Question on Stackoverflow
Solution 1 - JavaYishaiView Answer on Stackoverflow
Solution 2 - JavaMBCookView Answer on Stackoverflow
Solution 3 - JavaPaul TomblinView Answer on Stackoverflow
Solution 4 - JavaGraphics NoobView Answer on Stackoverflow
Solution 5 - JavaBilly Bob BainView Answer on Stackoverflow
Solution 6 - JavaKen LiuView Answer on Stackoverflow
Solution 7 - Javauser6811894View Answer on Stackoverflow
Solution 8 - JavaBasil BourqueView Answer on Stackoverflow
Solution 9 - JavaLukeView Answer on Stackoverflow