I need to convert raw Map to Map<string,string>, and I think I have to first convert the raw map to Map<Object,Object> and then convert it again to Map<String,String>.
code snippet goes like below.
Map obj1 = new HashMap();
obj1.put("key1", 1);
obj1.put("key2", false);
obj1.put("key3", 3.94f);
Map<Object, Object> obj2 = obj1;
Map<String, String> obj = new HashMap<String,String>();
for (Map.Entry<Object, Object> entry: obj2.entrySet()) {
obj.put(entry.getKey().toString(), entry.getValue().toString());
}
I guess it would work in any condition but I want to hear from others about possible danger of this code.(any possiblities for ClassCastException for example?)
Please also let me know if you have a better idea.
-- revised code
Map obj1 = new HashMap();
obj1.put(2, 1);
obj1.put(true, false);
obj1.put(4.4f, 3.94f);
Map<String, String> obj = new HashMap<String,String>();
for (Object k : obj1.keySet()){
obj.put(k.toString(), obj1.get(k).toString());
}
Since raw Map entries will contain key/value of Objects anyway, I think I don't need temporary Map<Object,Object>. Just iterating over each item works well and I don't see any issues so far.
If You Look out the Definition of HashMap in jdk 1.4 It was earlier Implements using Object Class when generics Concept not came.
When generics is Introduced this object is Replaced with <T>. But If you Still don't use Generics Type Safe then Internally this Statement new HashMap() reflects a instance of <Object, Object>. Better To use directly a
a new HashMap() is better idea. There should no need of Map <Object, Object> obj2.
So, GO For this.. a better approach.
Map obj1 = new HashMap();
obj1.put("key1", 1);
obj1.put("key2", false);
obj1.put("key3", 3.94f);
Map<Object, Object> obj2 = obj1;
Map<String, String> obj = new HashMap<String,String>();
for (Object obj_Entry : obj1.entrySet()) {
Map.Entry entry = (Map.Entry) obj_Entry; // This will Work Fine all Time.
obj.put(entry.getKey().toString(), entry.getValue().toString());
}
Your code will not generate ClassCastExceptions. Actually you are not doing any casting here. You just call the toString() method of every key/value pair to make it a string. As long as toString() returns a valid value of your objects. Your code will be fine.
But your code may produce NullPointerExceptions if your obj1 contain null keys or objects
obj1.put(null, "null value")
Also note that some key collisions may occur if toString() methods return same String value for two keys. This is unlikely but it is possible.
Related
I am trying to cast an Object to HashMap<String, Object> in a neat, robust way. So far, every way I tried produces compiler warnings or errors. What is the proper way to do it? I have checked the internet and tried the following:
HashMap<String, Object> map = (HashMap<String, Object>) object;
The code above gives an unchecked conversion warning.
HashMap<String, Object> map = new HashMap<>();
if (object instanceof Map<String, Object>){
map = (Map<String, Object>) object;
}
The code above gives an error, which says that objects cannot be compared to parameterized collections.
HashMap<String, Object> map = new HashMap<>();
if (object instanceof Map){
Map genericMap = (Map) object;
for (Object key : genericMap.keySet()){
if (key instanceof String){
map.put((String) key, genericMap.get(key));
}
else{
throw new KeyException();
}
}
}
The code above yields a warning that "Map is a raw type. References to generic type Map<K,V> should be parameterized."
So what would be the proper way to do this? Thank you in advance!
I am trying to cast an Object to HashMap<String, Object> in a neat, robust way. So far, every way I tried produces compiler warnings or errors. What is the proper way to do it?
There is no proper way to do it, supposing that "proper" implies both useful and type safe. Casting is the antithesis of type safety. Other than casts for arithmetic purposes, a safe cast is an unnecessary one.
There is not enough information to determine how to achieve what ultimately you are after, but generally speaking, that sort of thing revolves around writing true generic code instead of using type Object to funnel objects of unrelated type into the same methods, using instanceof to determine what you actually have, or casting.
Just add #SuppressWarnings("unchecked") to your method
#SuppressWarnings("unchecked")
public void myMethod(){
...
}
and you should be able to use
HashMap<String, Object> map = (HashMap<String, Object>) object;
I'm using Eclipse to help me clean up some code to use Java generics properly. Most of the time it's doing an excellent job of inferring types, but there are some cases where the inferred type has to be as generic as possible: Object. But Eclipse seems to be giving me an option to choose between a type of Object and a type of '?'.
So what's the difference between:
HashMap<String, ?> hash1;
and
HashMap<String, Object> hash2;
An instance of HashMap<String, String> matches Map<String, ?> but not Map<String, Object>. Say you want to write a method that accepts maps from Strings to anything: If you would write
public void foobar(Map<String, Object> ms) {
...
}
you can't supply a HashMap<String, String>. If you write
public void foobar(Map<String, ?> ms) {
...
}
it works!
A thing sometimes misunderstood in Java's generics is that List<String> is not a subtype of List<Object>. (But String[] is in fact a subtype of Object[], that's one of the reasons why generics and arrays don't mix well. (arrays in Java are covariant, generics are not, they are invariant)).
Sample:
If you'd like to write a method that accepts Lists of InputStreams and subtypes of InputStream, you'd write
public void foobar(List<? extends InputStream> ms) {
...
}
By the way: Joshua Bloch's Effective Java is an excellent resource when you'd like to understand the not so simple things in Java. (Your question above is also covered very well in the book.)
Another way to think about this problem is that
HashMap<String, ?> hash1;
is equivalent to
HashMap<String, ? extends Object> hash1;
Couple this knowledge with the "Get and Put Principle" in section (2.4) from Java Generics and Collections:
The Get and Put Principle: use an
extends wildcard when you only get
values out of a structure, use super
wildcard when you only put values into
a structure, and don't use a wildcard
when you both get and put.
and the wild card may start making more sense, hopefully.
It's easy to understand if you remember that Collection<Object> is just a generic collection that contains objects of type Object, but Collection<?> is a super type of all types of collections.
The answers above covariance cover most cases but miss one thing:
"?" is inclusive of "Object" in the class hierarchy. You could say that String is a type of Object and Object is a type of ?. Not everything matches Object, but everything matches ?.
int test1(List<?> l) {
return l.size();
}
int test2(List<Object> l) {
return l.size();
}
List<?> l1 = Lists.newArrayList();
List<Object> l2 = Lists.newArrayList();
test1(l1); // compiles because any list will work
test1(l2); // compiles because any list will work
test2(l1); // fails because a ? might not be an Object
test2(l2); // compiled because Object matches Object
You can't safely put anything into Map<String, ?>, because you don't know what type the values are supposed to be.
You can put any object into a Map<String, Object>, because the value is known to be an Object.
Declaring hash1 as a HashMap<String, ?> dictates that the variable hash1 can hold any HashMap that has a key of String and any type of value.
HashMap<String, ?> map;
map = new HashMap<String, Integer>();
map = new HashMap<String, Object>();
map = new HashMap<String, String>();
All of the above is valid, because the variable map can store any of those hash maps. That variable doesn't care what the Value type is, of the hashmap it holds.
Having a wildcard does not, however, let you put any type of object into your map. as a matter of fact, with the hash map above, you can't put anything into it using the map variable:
map.put("A", new Integer(0));
map.put("B", new Object());
map.put("C", "Some String");
All of the above method calls will result in a compile-time error because Java doesn't know what the Value type of the HashMap inside map is.
You can still get a value out of the hash map. Although you "don't know the value's type," (because you don't know what type of hash map is inside your variable), you can say that everything is a subclass of Object and, so, whatever you get out of the map will be of the type Object:
HashMap<String, Integer> myMap = new HashMap<>();// This variable is used to put things into the map.
myMap.put("ABC", 10);
HashMap<String, ?> map = myMap;
Object output = map.get("ABC");// Valid code; Object is the superclass of everything, (including whatever is stored our hash map).
System.out.println(output);
The above block of code will print 10 to the console.
So, to finish off, use a HashMap with wildcards when you do not care (i.e., it does not matter) what the types of the HashMap are, for example:
public static void printHashMapSize(Map<?, ?> anyMap) {
// This code doesn't care what type of HashMap is inside anyMap.
System.out.println(anyMap.size());
}
Otherwise, specify the types that you need:
public void printAThroughZ(Map<Character, ?> anyCharacterMap) {
for (int i = 'A'; i <= 'Z'; i++)
System.out.println(anyCharacterMap.get((char) i));
}
In the above method, we'd need to know that the Map's key is a Character, otherwise, we wouldn't know what type to use to get values from it. All objects have a toString() method, however, so the map can have any type of object for its values. We can still print the values.
when I declare a Map or Map <Object,Object> I can put anything in this Map
Map map = new HashMap();
map.put("");
but if I declare it as Map <?,?> I can put nothing in it
Map<?,?> map = new HashMap();
map.put("");
it will goes wrong why ?
Map<?,?> map = new HashMap<Integer, Integer>(); // compiles just fine!
? represents some fixed but unknown type. You can't put "" in a Map<Integer, Integer>, and a Map<?, ?> is allowed to be any type of Map, including a Map<Integer, Integer>.
In java collection Frame, ? means unknown type. You can only read elements from that, but can not add elements except for NULL value.
So you can compile fine like below:
Map<?,?> map = new HashMap();
map.put(null, null);
For this snippet code:
Map<?,?> map = new HashMap();
Map<?,?> means a Map typed to an unknown type.
The question mark (?), called the wildcard,the wildcard means "the value type parameter could be anything", it doesn't mean "you can use this as if it were anything you want it to be".
For more info go to link
How can I pass in a new HashMap in the most canonical (simplest, shortest hand) form?
// 1. ? (of course this doesn't work)
passMyHashMap(new HashMap<String, String>().put("key", "val"));
// 2. ? (of course this doesn't work)
passMyHashMap(new HashMap<String, String>(){"key", "val"});
void passMyHashMap(HashMap<?, ?> hm) {
// do stuff witih my hashMap
}
Create it, initialize it, then pass it:
Map<String,String> myMap = new HashMap<String,String>();
myMap.put("key", "val");
passMyHashMap(myMap);
You could use the "double curly" style that David Wallace mentions in a comment, I suppose:
passMyHashMap(new HashMap<String,String>(){{
put("x", "y");
put("a", "b");
}});
This essentially derives a new class from HashMap and sets up values in the initializer block. I don't particularly care for it (hence originally not mentioning it), but it doesn't really cause any problems per se, it's more of a style preference (it does spit out an extra .class file, although in most cases that's not a big deal). You could compress it all to one line if you'd like, but readability will suffer.
You can't call put and pass the HashMap into the method at the same time, because the put method doesn't return the HashMap. It returns the old value from the old mapping, if it existed.
You must create the map, populate it separately, then pass it in. It's more readable that way anyway.
HashMap<String, String> map = new HashMap<>();
map.put("key", "val");
passMyHashMap(map);
HashMap< K,V>.put
public **V** put(K key,V value)
Associates the specified value with the specified key in this map. If
the map previously contained a mapping for the key, the old value is
replaced.
Returns the previous value associated with key, or null if there was
no mapping for key. (A null return can also indicate that the map
previously associated null with key.)
As you can see, it does not return the type HashMap<?, ?>
You can't do that. What you can do is create a factory that allow you to do so.
public class MapFactory{
public static Map<String, String> put(final Map<String, String> map, final String key, final String valeu){
map.put(key, value);
return map;
}
}
passMyHashMap(MapFactory.put(new HashMap<String, String>(),"key", "value"));
Although I can't image a approach that would need such implementation, also I kinda don't like it. I would recommend you to create your map, pass the values and just then send to your method.
Map<String, String> map = new HashMap<String, String>();
map.put("key","value");
passMyHashMap(map);
I have a problem in JAVA when i'm trying to return a HashMap that I have added to a list of type: List<Object>. I know I can use other type of lists, but I need to use List<Object>
List<Object> listOfObjects = new ArrayList<Object>();
HashMap<String, String> hashmap = new HashMap<String,String>();
hashmap.put("x", "foo");
hashmap.put("y", "bar");
listOfObjects.add(hashmap);
for (int i = 0; i < listOfObjects.size(); i++) {
System.out.println(listOfObjects.get(i));
}
I have added my hashmap to my listOfObject, but how do I get the HashMap from the listOfObject such that I can use the HashMap-commands. fx: hashmap.get("x) and it will return "foo".
Normally i thought i could just write: listOfObjects.get(0).get("x") and it would return "foo" but that does not work.
If anyone know another work around that's find but I just need to use a List.
Normally i thought i could just write: listOfObjects.get(0).get("x") and it would return "foo" but that does not work.
No, it wouldn't - because the type of listOfObjects.get(0) is just Object. How do you expect the compiler to know that it's meant to be a map?
You can use:
HashMap<String, String> map = (HashMap<String, String>) listOfObjects.get(0);
// Use map...
... but be aware that due to the nature of generics in Java, that cast isn't really ensuring that all the key/value pairs in the map are "string to string". The cast would work even if you'd originally used:
Map<Integer, Integer> badMap = new HashMap<Integer, Integer>();
badMap.put(0, 10);
listOfObjects.add(badMap);
You'll get a warning for this, but it's important to understand what it means. It's not clear what your use case is, but if you can make it more strongly typed (perhaps create a new class which contains a Map<String, String>?) that would be good. Is every element of your list going to be a map? If so, why are you using List<Object> rather than a more strongly-typed list? If some elements aren't going to be maps, how can you tell which ones will be? (These are the sort of things you should be thinking about carefully.)
I hope this will help u..
List<Object> listOfObjects = new ArrayList<Object>();
HashMap<String, String> hashmap = new HashMap<String,String>();
hashmap.put("x", "foo");
hashmap.put("y", "bar");
listOfObjects.add(hashmap);
for (int i = 0; i < listOfObjects.size(); i++) {
System.out.println(((HashMap<String, String>)listOfObjects.get(i)).get("x"));
}
Normally as your list is of type of object . so first cast it to HashMap type and then get the value from map
please notice the following code
System.out.println(((HashMap<String, String>)listOfObjects.get(i)).get("x"));