Java HashMap<String, String> has LinkedHashMap in value - java

So I have a strange issue with a HashMap and not sure how to access the value. I have a HashMap returned to me from an API that is suppose to be HashMap<String, String>. One of the values is actually a LinkedHashMap. I've tried casting it, but since it is a HashMap that is <String, String> it's giving me an error that it's not possible. Is there anyway to get a LinkedHashMap value out of a HashMap that is <String, String>?
I have tried this with no luck: ((HashMap)userInfo.get("key")).get("key");
Could not complete request <java.lang.ClassCastException:
java.util.LinkedHashMap cannot be cast to java.lang.String>java.lang.ClassCastException:
java.util.LinkedHashMap cannot be cast to java.lang.String
This is really ugly looking, but I was actually able to get it out of the HashMap with this:
(HashMap) ((HashMap)((HashMap)userInfo).get("picture")).get("data");
Thanks to Jeroen for sending me down the right path.

Brackets placement.
Try
(((HashMap)userInfo).get("key")).get("key");
You have to cast before you use .get() (assuming your attempt is actually valid and it is just a matter of brackets).

Convert typed map first to untyped map and then check type of each value. Map interface is implemented by HashMap and LinkedHashMap classes so you'll most likely want to use it instead of more specific types.
HashMap<String, String> typedMap = ...
Map untypedMap = (Map) typedMap;
Object mapValue = untypedMap.get("key");
if(mapValue instanceof Map) {
// handle as Map
}
if(mapValue instanceof String) {
// handle as String
}

If it is a LinkedHashMap and you cast it to a HashMap you will have probelms.
You could instead treat it as a Map:
Map m = userInfo.get("key");

Related

casting generic-type list of maps

I'm trying to use spigot's ConfigurationSection#getMapList which is of the type <java.util.List<java.util.Map<?,?>>>.
I know that in this specific case the values it returns will be of the type
List<Map<String, List<Integer>>>.
So I've written this:
List<Map<String, List<Integer>>> configSpawnpoints = this.getConfig().getMapList("key");
but get the error:
incompatible types: java.util.List<java.util.Map<?,?>> cannot be converted to
java.util.List<java.util.Map<java.lang.String,java.util.List<java.lang.Integer>>>
How can I cast my List<Map<?,?>> to a List<Map<String, List<Integer>>> ?
The wildcard return here implies that the API can't guarantee that it knows what types are going to be contained in the map. Additionally, you can't force it to cast at compile-time since there's no concrete guarantee. Your best hope is to cast this manually to a Map when you want to access it and deal with the error(s) at runtime.
List<Map<?, ?>> configSpawnpoints = this.getConfig().getMapList("key");
// to use it
Map<Integer, List<String>> mapPoint = (Map) configSpawnpoints.get(0);

Defining Maps, Sets, etc and then passing/getting them

I've read that when you define a {Map, Set, Etc} it is good practice use the interface name as so:
Map<Integer, String> map = new LinkedHashMap<Integer, String>();
instead of:
LinkedHashMap<Integer, String> map = new LinkedHashMap<Integer, String>();
I'm not sure why this is, but I've put it to practice in hopes I will understand at a later time. Maybe that time has come.
So I create a class that defines one and create a getter for the Map:
class Data{
private Map<Integer, String> map;
public Data(){
map = new LinkedHashMap<Integer, String>();
//dynamically put some things into the map
}
public Map<Integer, String> getMap(){
return map;
}
}
Now I come to my first impasse. I can't return a LinkedHashMap, I have to return a Map.
So in another class I get that Map
class Foo{
public Foo{
Data data = new Data();
Map<Integer, String> map = data.getMap();
}
}
Can someone explain what is happening to map when it gets passed?
Is it still a LinkedHashMap?
Is the data changed at all?
What would happen to the order of the Map if, after calling getData(), I put something in the Map?
Why wouldn't/shouldn't I just define the Map as in the second code snippet?
Is my method of getting the map done in ignorance?
Should I just make map public?
Now I come to my first impasse. I can't return a LinkedHashMap
Here's the misunderstanding: you can return a LinkedHashMap, because a LinkedHashMap is a Map, a particular sort of Map, but a Map anyway.
Can someone explain what is happening to map when it gets passed?
When it's passed, it is seen as any Map, like incognito, but it remains the same.
Is it still a LinkedHashMap?
Yes.
Is the data changed at all?
No.
What would happen to the order of the Map if, after calling getData(), I put something in the Map?
This is another topic.
Why wouldn't/shouldn't I just define the Map as in the second code snippet?
You needn't do that, since a LinkedHashMap is a Map (on the other hand, a Map is not necessarily a LinkedHashMap).
Is my method of getting the map done in ignorance?
Should I just make map public?
No.
You may want your variable to be able do what it needs to do and still be as flexible as possible in the way it does that. So your variable should be of the type that covers all your needed functionality but is as high as possible in hirachy.

Are there performance benefits to creating a Hashmap with defined types vs. Objects?

When should I do one, and when should I do the other, especially in cases where both suffice? For example, consider if I need a Hashmap of type <String, String>. Is there any reason to do a hashmap of type <Object, Object>?
Are there performance benefits/penalties for either, or is it an issue of clarity?
I suppose you are using HashMap like this:
Map map = new HashMap();
map.put("aKey","value");
String v =(String)map.get("aKey");
You can use it like this:
Map<String,String> map= new HashMap<String,String>();
map.put("aKey","value");
String v = map.get("aKey");
Because it is used as a polymorphic reference. You want String I may want my own custom Class. So make it generic they have used Objects. However you can use generics to avoid cast.
That depends on how you initialize it. According to the JavaDocs, the HashMap can take the data types of what it is storing, so if you do this:
Map hashMap = new HashMap();
map.put("hello", "abc");
You would need to cast to get back your keys and data. However, if you do something like so:
Map<String, String> hashMap = new HashMap<>();
map.put("hello", "abc");
You no longer need to cast the objects that you have. You can take a look here for more information on Generics.
//If you dont make generic then you have to cast the object
HashMap myMap = new HashMap();
// If you make it generic then you dont have to cas the object
HashMap<String, String> myMap2 = new HashMap<String, String>();
An additional clarification is that .... objects are never stored inside a HashMap. Instead the reference/identity of the object is kept inside.
On retrieval, actual reference is picked from the location (given by HashMap) and provided to caller.
Purpose of Java generics is to apply compile time checks only; it has noting to do with run-time.
What if reference points to an Integer and type-cast is expecting a String?
Generics simplify the programming and helps in avoiding Class Cast errors at run-time.

how to declare variable like this-- ArrayList LinkedhashMap

how to declare variable like this-- ArrayList LinkedhashMap.
Map<String, ArrayList<LinkedHashMap<KeyType, ValueType>> maps;
KeyType and ValueType are placeholders, I don't know the real types. And the real declaration should use interfaces. But that's the closest to answer your question.
(The better declaration:
Map<String, List<Map<KeyType, ValueType>> maps;
We map lists of maps to string values. That's the explanation for this datastructure
)
Well if you are using Java 1.5 or greater , you can make use of Generics
//This approach is type safe.
List<LinkedHashMap<KeyType,ValueType>> myListOfMaps = ArrayList<LinkedHashMap<KeyType, ValueType>>();
for Java less that 1.5 use normal Arraylist.
List myListOfMaps = new ArrayList (); //But with this approach its not type safe ,
//because any object type can be inserted
Now to create a Map of ListsofMaps
Map<String, List<Map<KeyType, ValueType>> maps = new HashMap <String, List<Map<KeyType, ValueType>>();
maps.put("rows",myListOfMaps );
This link will give you Why Use Generics ?
Check this Generic tutorial for more info

Is this possible in Java: Map<SomeObject, Map<SomeOtherObject>>?

Is this possible in Java: Map<SomeObject, Map<SomeOtherObject>>? I'm trying Map<Integer, Map<String>> am getting an
"Incorrect number of arguments for
type Map; it cannot be
parameterized with arguments "
error.
Every Map needs to be parametrized on two types; your second (nested) Map has only one.
A Map maps keys to values, so Map<String> is incorrect. So you'd need something like Map<String, Object>.
You need a second argument on your second Map<>. Perhaps you mean Map<Integer, Map<String, String>>?
No, not really like that. You need to give a type for both Key and Value for the second "inner" Map, this is ok:
Map<SomeObject, Map<SomeOtherObject, Object>>
Just like with the outer Map, where the Key is SomeObject, and Value is the inner Map. So, if you add a value specification for the inner Map is, that would be ok.

Categories