java: HashMap<String, int> not working - java

HashMap<String, int> doesn't seem to work but HashMap<String, Integer> does work.
Any ideas why?

You can't use primitive types as generic arguments in Java. Use instead:
Map<String, Integer> myMap = new HashMap<String, Integer>();
With auto-boxing/unboxing there is little difference in the code. Auto-boxing means you can write:
myMap.put("foo", 3);
instead of:
myMap.put("foo", new Integer(3));
Auto-boxing means the first version is implicitly converted to the second. Auto-unboxing means you can write:
int i = myMap.get("foo");
instead of:
int i = myMap.get("foo").intValue();
The implicit call to intValue() means if the key isn't found it will generate a NullPointerException, for example:
int i = myMap.get("bar"); // NullPointerException
The reason is type erasure. Unlike, say, in C# generic types aren't retained at runtime. They are just "syntactic sugar" for explicit casting to save you doing this:
Integer i = (Integer)myMap.get("foo");
To give you an example, this code is perfectly legal:
Map<String, Integer> myMap = new HashMap<String, Integer>();
Map<Integer, String> map2 = (Map<Integer, String>)myMap;
map2.put(3, "foo");

GNU Trove support this but not using generics. http://trove4j.sourceforge.net/javadocs/gnu/trove/TObjectIntHashMap.html

You cannot use primitive types in HashMap. int, or double don't work. You have to use its enclosing type. for an example
Map<String,Integer> m = new HashMap<String,Integer>();
Now both are objects, so this will work.

int is a primitive type, you can read what does mean a primitive type in java here, and a Map is an interface that has to objects as input:
public interface Map<K extends Object, V extends Object>
object means a class, and it means also that you can create an other class that exends from it, but you can not create a class that exends from int.
So you can not use int variable as an object. I have tow solutions for your problem:
Map<String, Integer> map = new HashMap<>();
or
Map<String, int[]> map = new HashMap<>();
int x = 1;
//put x in map
int[] x_ = new int[]{x};
map.put("x", x_);
//get the value of x
int y = map.get("x")[0];

You can use reference type in generic arguments, not primitive type.
So here you should use
Map<String, Integer> myMap = new HashMap<String, Integer>();
and store value as
myMap.put("abc", 5);

Related

Generics Handling LinkedHashMap<String, LinkedHashMap>

I have never been that good in Generics but I used SnakeYaml.
Is there a way to let me fix this code
public class MyService{
private static Map<String, LinkedHashMap> myYamlMap;
public static void filter(Map<String, String>){
//myYaml map reads the YAML File using SnakeYaml
//Snake Yaml returns data in this format <String,LinkedHashMap>
Yaml yaml = new Yaml();
Object object = yaml.load(reader);
Map<String, LinkedHashMap> myYamlMap = (Map<String, LinkedHashMap>)object;
LinkedHashMap<String, LinkedHashMap> mainMap = (LinkedHashMap<String, LinkedHashMap>)myYamlMap.get("sample");
}
}
and get away with this compile time warnings?
Multiple markers at this line
- Line breakpoint:MyService [line: 69] - filter(Map<String, String>)
- Type safety: Unchecked cast from LinkedHashMap to LinkedHashMap<String,LinkedHashMap>
- LinkedHashMap is a raw type. References to generic type LinkedHashMap<K,V> should be
parameterized
- LinkedHashMap is a raw type. References to generic type LinkedHashMap<K,V> should be
parameterized
Snakeyaml..uses LinkedHashMap in its construct and I wanted to get away with the casting.
Given your code:
private static Map<String, LinkedHashMap> myYamlMap;
LinkedHashMap<String, LinkedHashMap> mainMap = (LinkedHashMap<String, LinkedHashMap>)myYamlMap.get("sample");
This doesn't make sense.
private static Map<String, LinkedHashMap> myYamlMap;
This should probably be
private static Map<String, Map<Key, Value>;
myYamlMap = new LinkedHashMap<String, Map<Key, Value>>;
myYamlMap.put("key1", new LinkedHashMap<Key,Value>();
for some Key and Value types, which aren't specified in your code...
OR something more complex -- see below
LinkedHashMap<String, LinkedHashMap> mainMap = (LinkedHashMap<String, LinkedHashMap>)myYamlMap.get("sample");
Your use of get here seems to imply that myYamlMap should be
private static Map<String, Map<String, Map<Key, Value>> myYamlMap;
myYamlMap = new LinkedHashMap<String, Map<String, Map<Key,Value>>>;
Map<Key,Value> temp = new LinkedHashMap<Key,Value>();
temp.put(k1, value1);
myYamlMap.put("sample", temp);
since you seem to be expecting get() to return a Map<String,Map<Key,Value>> from within the outer collection.
NOW you can do
Map<String, Map<Key,Value>> mainMap = myYamlMap.get("sample");
The reason for using the Map interface is that nowhere in your code do you use methods specific to LinkedHashMap so declarations should all be using just Map<...> except when instantiating the maps.

Why <String, String> entry allowed for HashMap<Integer, String>()?

I have HashMap which generic type <Integer, String> i.e. key should be an Integer and value should be String for this HashMap.
I wrote bellow code which put String and getting no compilation and runtime error. Why?
Map map = new HashMap<Integer, String>();
map.put("a", "one");
System.out.println(map);
OUTPUT:
{a=one}
I have HashMap which generic type <Integer, String> ...
No you do not!
Map map = new HashMap<Integer, String>();
Means you have just a Map (because of Map map =). If you want Map<Integer, String> you must use:
Map<Integer, String> map = new HashMap<Integer, String>();
or, in later versions of Java
Map<Integer, String> map = new HashMap<>();
Added
The reason for this is that the right-hand-side of the assignment is a separate process and is evaluated first. In your case it creates a HashMap<Integer, String>.
Next the assignment happens, the compiler checks that HashMap<Integer, String> can be cast to Map (which is equivalent to Map<Object,Object> BTW) and the assignment is performed. From then on all references to map treat it as type Map<Object,Object> and can therefore hold any type for key or value.
You are adding content to Map map declared without specifying any generics types.
If you declare the map this way the compilator doesn't know how to check the map content.
If you change your map declaration to
Map<Integer, String> map = new HashMap<>();
Then you will have a compilation error.
Map map = new HashMap<Integer, String>();
Here your definition is type specified, however declaration is not. So, you are able to add any type to map.
The proper way for generic map declaration is
Map<Integer, String> map = new HashMap<Integer, String>();
or in new versions of Java, you can skip type in defintion.
Map<Integer, String> map = new HashMap<>();
Defining generics on the right side is more or less obsolete (grey font).
Following code wouldn't compile:
Map<Integer, String> map = new HashMap<>();
map.put("a", "one");
System.out.println(map);
with this explanation:
Wrong 1st argument type. Found: 'java.lang.String', required: 'java.lang.Integer'

Have complication with Map?

I have this question regarding generics.Can anybody explain me why the options 4 and 6[i know about this option]are correct?
Consider the following code:
import java.util.*;
public class TestClass
{
public static void main(String[] args)
{
// put declaration here
m.put("1", new ArrayList()); //1
m.put(1, new Object()); //2
m.put(1.0, "Hello"); //3
System.out.println(m);
}
}
How can 'm' be declared such that the above code will compile and run without errors?
Map m = new TreeMap();
Map<Object, Object> m = new TreeMap<Object, Object>();
Map<Object, ?> map = new LinkedHashMap<Object, Object>();
Map<Object, ? super ArrayList> m = new LinkedHashMap<Object, ArrayList>();will work
if lines //2 and //3 are commented out.
Map<Object, ? super ArrayList> m = new LinkedHashMap<Object, ArrayList>(); will work if lines //1 and //3 are commented out.
Map m = new HashMap();
For understanding this problem, look at the generic signature of the Map#put method you are using here. It states:
V put(K key, V value)
what means that you can put a key that is assignable to the generic type of the Map's key type K and a value that is assignable to the generic type of the Map's value type V. This must be true for all your key-value pairs you put into the map. From your code, you are putting the following keys into the map:
A String by the literal "1"
An Integer by the boxed int literal 1.
A Double by the boxed double literal 1.0.
The only common super type of these objects is the Object type which is required for K in order to allow all these objects to be used as a key.
For the values you have:
A ArrayList instance.
An Object instance
A String by the literal "Hello"
Again, the only common super type of these objects is the Object type which is required for V in order to allow all these objects to be used as a map value.
As a result, only Map instances with the generic signature Map<Object, Object> are permitted. What implementation of the Map interface you choose is up to you, as long as it is assignable to the variable type of the map, i.e. you can use a LinkedHashMap, a TreeMap or a HashMap since they only differ in the way they store their data. For the generic type of the variables, note that the use of wildcards ? or ? extends ... for your variable will result in you not being able to put values into the map anymore. The tutorial I linked explains why.
As for the types with a non-generic signature you are using, they behave similar to Maps with the generic signature <Object, Object>. Such raw types should however not longer be used after the introduction of Java 5.
With all this information, you can answer your (exam) question yourself.
Number 4 is correct for line 1, because "1" is String which has Object superclass and ? super ArrayList means that you can use ArrayList or any superclass of ArrayList.
Number 6 is correct because you are using untyped(raw) map, so it's similar to:
Map<Object, Object> m = new HashMap<Object, Object>();
To store such values you can use Map, but it's not a really good choice. You shouldn't use untyped collections at all. Think how you can change your design to not use such map.

Newbie generic parameter qu estion... <T>

Okay so can i achive this somehow:
String myString = "someString";
Class myClass = myString.getClass();
HashMap<mClass, Integer> = new HashMap<myClass, Integer>();
So i would like to create a new hashmap, with class type of the key of my variables like Integer or String...
This is not possible. I'll walk you through the possibilities.
You could create a helper method, using generics. This will work because of all generics are compiled into simple Objects.
public static <T> Map<T, Integer> createMap(Class<T> cl)
{
return new HashMap<T, Integer>();
}
Now, you could use it like this:
Map<String, Integer> map = createMap(String.class);
However, this will require you to know what T is at compile time. So this won't work:
String str = "Test";
Class cl = str.getClass();
Map<String, Integer> map = createMap(cl); // Doesn't compile.
So, to conclude, this helper method isn't worth anything, because you could simply write:
Map<String, Integer> map = new HashMap<String, Integer>();
Due to type erasure this would not work.
A possible (but more verbose way) is to create a factory method that returns a Map based on the passed argument, eg:
MapFactory.create(String.class);
EDIT: In answer to #millimoose comment about this being not different from direct instantiation (which is true):
You could try to implement your own Map or decorate or extend the HashMap implementation so that it retains type information.

Regarding querying Java Map with values as array of string.

I have map of string and array of strings as:
private static Map cacheTimeStamp = new HashMap<String, String[]>();
now how do i get value of this Map, i want to return array of String[] back to the calling function, tried using cacheTimeStamp.get("stringKey") but it returns object and i want to get array of strings out.
Define your map like this:
private static Map<String, String[]> cacheTimeStamp = new HashMap<String, String[]>();
Problem is that you are defining an open map without specifying map's key and value object types. Which is essentially a key of type java.lang.Object and a value of type java.lang.Object.
You didn't define the generics.
Map<String, String[]> cacheTimeStamp = new HashMap<String, String[]>();
It actually did return an array of Strings, but strictly you don't know when you don't include the generics in the definition. That's why the IDE tells you it will be an Object. Make sure you are beware of the fact that an array is an Object.
You actually get an String[].
I see two options:
Cast the return value to an String[]:
String[] myEntry = (String[]) cacheTimeStamp.get("stringKey");
(My preference) Add type arguments to the map:
private static Map cacheTimeStamp = new HashMap();
// ...
String[] myEntry = cacheTimeStamp.get("stringKey");

Categories