Properties properties = new Properties();
Map<String, String> map = new HashMap<String, String>(properties);// why wrong?
java.util.Properties is a implementation of java.util.Map, And java.util.HashMap's constructor receives a Map type param. So, why must it be converted explicitly?
This is because Properties extends Hashtable<Object, Object> (which, in turn, implements Map<Object, Object>). You attempt to feed that into a Map<String, String>. It is therefore incompatible.
You need to feed string properties one by one into your map...
For instance:
for (final String name: properties.stringPropertyNames())
map.put(name, properties.getProperty(name));
The efficient way to do that is just to cast to a generic Map as follows:
Properties props = new Properties();
Map<String, String> map = (Map)props;
This will convert a Map<Object, Object> to a raw Map, which is "ok" for the compiler (only warning). Once we have a raw Map it will cast to Map<String, String> which it also will be "ok" (another warning). You can ignore them with annotation #SuppressWarnings({ "unchecked", "rawtypes" })
This will work because in the JVM the object doesn't really have a generic type. Generic types are just a trick that verifies things at compile time.
If some key or value is not a String it will produce a ClassCastException error. With current Properties implementation this is very unlikely to happen, as long as you don't use the mutable call methods from the super Hashtable<Object,Object> of Properties.
So, if don't do nasty things with your Properties instance this is the way to go.
You could use Google Guava's:
com.google.common.collect.Maps.fromProperties(Properties)
How about this?
Map properties = new Properties();
Map<String, String> map = new HashMap<String, String>(properties);
Will cause a warning, but works without iterations.
The Java 8 way:
properties.entrySet().stream().collect(
Collectors.toMap(
e -> e.getKey().toString(),
e -> e.getValue().toString()
)
);
Properties implements Map<Object, Object> - not Map<String, String>.
You're trying to call this constructor:
public HashMap(Map<? extends K,? extends V> m)
... with K and V both as String.
But Map<Object, Object> isn't a Map<? extends String, ? extends String>... it can contain non-string keys and values.
This would work:
Map<Object, Object> map = new HashMap<Object, Object>();
... but it wouldn't be as useful to you.
Fundamentally, Properties should never have been made a subclass of HashTable... that's the problem. Since v1, it's always been able to store non-String keys and values, despite that being against the intention. If composition had been used instead, the API could have only worked with string keys/values, and all would have been well.
You may want something like this:
Map<String, String> map = new HashMap<String, String>();
for (String key : properties.stringPropertyNames()) {
map.put(key, properties.getProperty(key));
}
I would use following Guava API:
com.google.common.collect.Maps#fromProperties
Properties properties = new Properties();
Map<String, String> map = Maps.fromProperties(properties);
If you know that your Properties object only contains <String, String> entries, you can resort to a raw type:
Properties properties = new Properties();
Map<String, String> map = new HashMap<String, String>((Map) properties);
The problem is that Properties implements Map<Object, Object>, whereas the HashMap constructor expects a Map<? extends String, ? extends String>.
This answer explains this (quite counter-intuitive) decision. In short: before Java 5, Properties implemented Map (as there were no generics back then). This meant that you could put any Object in a Properties object. This is still in the documenation:
Because Properties inherits from Hashtable, the put and putAll methods
can be applied to a Properties object. Their use is strongly
discouraged as they allow the caller to insert entries whose keys or
values are not Strings. The setProperty method should be used instead.
To maintain compatibility with this, the designers had no other choice but to make it inherit Map<Object, Object> in Java 5. It's an unfortunate result of the strive for full backwards compatibility which makes new code unnecessarily convoluted.
If you only ever use string properties in your Properties object, you should be able to get away with an unchecked cast in your constructor:
Map<String, String> map = new HashMap<String, String>( (Map<String, String>) properties);
or without any copies:
Map<String, String> map = (Map<String, String>) properties;
this is only because the constructor of HashMap requires an arg of Map generic type and Properties implements Map.
This will work, though with a warning
Properties properties = new Properties();
Map<String, String> map = new HashMap(properties);
You can use this:
Map<String, String> map = new HashMap<>();
props.forEach((key, value) -> map.put(key.toString(), value.toString()));
First thing,
Properties class is based on Hashtable and not Hashmap. Properties class basically extends Hashtable
There is no such constructor in HashMap class which takes a properties object and return you a hashmap object. So what you are doing is NOT correct. You should be able to cast the object of properties to hashtable reference.
i use this:
for (Map.Entry<Object, Object> entry:properties.entrySet()) {
map.put((String) entry.getKey(), (String) entry.getValue());
}
When I see Spring framework source code,I find this way
Properties props = getPropertiesFromSomeWhere();
// change properties to map
Map<String,String> map = new HashMap(props)
Related
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.
i´m trying to make a casting of Hasmap
I have this hasmap:
Map<String, Object> requestargs = new Map<String, Object>();
Other side i have a method who bring me a hashmap of: Map<String, Document>
MultipartForm form = MgnlContext.getWebContext().getPostedForm();
The method is getDocuments();
I need to put the return of this method in my hashmap making something like this:
requestargs = form.getDocuments();
But i don´t know how to cast this Hasmap og (String,Document) to (String,Object)
Thanks
Unless you can use a wildcard
Map<String, ? extends Object> requestargs
You will need to copy the map into a new map:
requestargs = new HashMap<String, Object>(form.getDocuments());
The two types are not related directly. Were you able to make the assignment directly (or via casting) it would be possible to insert a value with non-Document type into the map, and that would be type-unsafe:
Map<String, Document> docs = form.getDocuments();
Map<String, Object> requestargs = docs; // not actually allowed
requestargs.put("Foo", new Object());
for (Document doc : docs.values()) {
// doc isn't necessarily a Document! ClassCastExceptions abound.
}
To prevent this problem happening, such an assignment is forbidden by the type system.
The wildcard works because it makes it impossible to call put on the map, since there is no way to know what types can be put into the map safely.
Can I do something like this in Java?
HashMap<String, Child> childMap=new HashMap<String, Child>();
HashMap<String, childMap.typeName> parentMap=new HashMap<String, childMap.typeName>();
//instead of
HashMap<String, HashMap<String, Child>> parentMap=new HashMap<String, HashMap<String, Child>>();
or something like this
HashMap<String, HashMap<String, Child>> parent1=new HashMap<String, HashMap<String, Child>>();
parent1.typeName parent2=new parent1.typeName;
Because some time, if the map level is too deep or too complex, it is very hard to write and read.
Abbreviations are possible by defining a subclass:
class Str2Child extends HashMap<String, Child>>{}
class Str2Map extends HashMap<String,Str2Child>{}
Str2Map parent1 = new Str2Map();
No but you could shorten it if you're using Java 7 or higher. The compiler can infer the type parameters from the left side of the assignment and you can skip them altogether while creating the object HashMap<String, HashMap<String, Child>> parentMap = new HashMap<>();
In older versions of Java, you could resord to Guava's Maps class and its newHashMap method. HashMap<String, HashMap<String, Child>> parentMap = Maps.newHashMap();
Another thing you could possibly do is create a type that implements a certain specification of the generic HashMap.
public class HashMapStringChild extends HashMap<String, Child> {
}
and then use it as a type parameter
HashMap<String, HashMapStringChild> parent2 = new HashMap<>();
but personally, I find this a bit of a stretch. I certainly wouldn't overuse it and I'd be careful extending the collection classes.
Addendum
You should also note that you're effectively binding your API to a specific implementation of the Map interface (HashMap), or even worse, in case of introducing the new class (HashMapStringChild), to a specific, non-standard implementation.
What if at some point, you decide to keep your Child objects sorted at all times? You could do this by switching to a TreeMap but that would mean a big deal of refactoring.
You would be better off basing your API on a more general interface. This way you could switch from
Map<String, Map<String, Child>> map = new HashMap<String, HashMap<String, Child>>();
to
Map<String, Map<String, Child>> map = new HashMap<String, TreeMap<String, Child>>();
or
Map<String, Map<String, Child>> map = new TreeMap<String, TreeMap<String, Child>>();
or any other implementation without a hassle.
If you really want to make the map of String to Child a specific type, you could introduce an interface
public interface MapStringToChild extends Map<String, Child> {
}
Then you could keep your reference types general and use HashMap<String, Child>, TreeMap<String, Child>, HashMapStringChild or literally any other implementation mapping a String to a Child interchangeably, while keeping the code short.
I've been trying to create a class that will model a scenario I've come up with. It will involve a map with string keys and values.
I need to create an instance variable used to reference the map object, and a constructor that creates the empty map and assigns it to the map instance variable.
I've been messing around with map objects but not creating a class using them, and I've hit a mental block!
What's the proper way to actually get a map object?
public class TheClass {
private Map<String, String> theMap;
public TheClass() {
theMap = new HashMap<>();
}
}
public class Demo {
Map<String,String> map = null;
public Demo()
{
map = new HashMap<String,String>();
}
}
If you want to use HashMap which is Map implementation you can do it like that:
Map<String, String> map = new HashMap<String, String>();
or
Map<String, String> map = new HashMap<>();
in Java 7.
You can also use other implementations like TreeMap.
You can use the HashMap which is an implementation of Map
http://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html
Map<String,String> map = new HashMap<String,String>();
map.put("key1", "Value1");
map.put("Key2", "Value2");
I have Two Maps
Map<String, String> filterMap
Map<String, Object> filterMapObj
What I need is I would like to convert that Map<String, String> to Map<String, Object>.
Here I am using the code
if (filterMap != null) {
for (Entry<String, String> entry : filterMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
Object objectVal = (Object)value;
filterMapObj.put(key, objectVal);
}
}
It works fine, Is there any other ways by which I can do this without iterating through all the entries in the Map.
Instead of writing your own loop that calls put, you can putAll, which does the same thing:
filterMapObj.putAll(filterMap);
(See the Javadoc.)
And as Asanka Siriwardena points out in his/her answer, if your plan is to populate filterMapObj immediately after creating it, then you can use the constructor that does that automatically:
filterMapObj = new HashMap<>(filterMap);
But to be clear, the above are more-or-less equivalent to iterating over the map's elements: it will make your code cleaner, but if your reason for not wanting to iterate over the elements is actually a performance concern (e.g., if your map is enormous), then it's not likely to help you. Another possibility is to write:
filterMapObj = Collections.<String, Object>unmodifiableMap(filterMap);
which creates an unmodifiable "view" of filterMap. That's more restrictive, of course, in that it won't let you modify filterMapObj and filterMap independently. (filterMapObj can't be modified, and any modifications to filterMap will affect filterMapObj as well.)
You can use the wildcard operator for this.
Define filterMapObj as Map<String, ? extends Object> filterMapObj and you can directly assign the filterMap to it. You can learn about generics wildcard operator
You can simply write
Map<String, Object> filterMapObj = new HashMap<>(filterMap);
You can use putAll method to solve the problem.The Object is the father class of all objects,so you can use putAll without convert.