How to create a map instance variable - java

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");

Related

Good design pattern choice for initializing a hashmap in Java

I have a non-static class in Java that has a static hashmap field. The hashmap should be initialized with some key-value pairs generated by code. The hashmap is not to be changed after that.
How should this be achieved? Should I just create a static init method and make sure to run this once before using the class, or are there better ways of doing it?
You can use a static initializer block in your class.
e.g.
private static Map<String, String> myMap;
static {
HashMap<String,String> map = new HashMap<String,String>();
map.put("foo","bar");
myMap = Collections.unmodifiableMap(map);
}
You can easily create immutable maps with Google Guava library:
private static Map<String, String> map = ImmutableMap.of(
"key1", "value1",
"key2", "value2");
If you want to use it for many values then builder() is provided.

Can I use type of a variable to declare another variable in Java?

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.

Converting java.util.Properties to HashMap<String,String>

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)

Store a Map object inside another Map

I have for instance this Map:
Map<String, Integer> map = new HashMap<String,Integer>();
than I put some values:
map.put("a", 2);
map.put("b", 3);
Than I have this class to serialize this object:
public class MapObject implements Serializable {
private static final long serialVersionUID = 1L;
Map<String, Integer> map = new HashMap<String, Integer>();
public MapObject(Map<String, Integer> map) {
this.map = map;
}
}
I do this because I'm working with sockets and I want to pass a map object from the client to the server using ObjectInputStream and ObjectOutputStream.
Now what I want to ask is if I can store this Map object in the server, for instance
MapObject mo;
Is it possible to store this object in another Map?
Regards
You are mixing two questions together. Don't know which you are asking:
Can you transport a hierarchical map thro ObjectOutputStream?
How to map a map to a map?
If you are asking question 2, you should not mention even mention question 1 because it confuses the question. OR are you asking both questions?
Answer to question 2:
Map<String, Map<?,?>> mapOfMap = new HashMap<String, Map<?,?>>();
Map<String, Integer> mapA = new HashMap<String, Integer>();
mapOfMap.put("a", mapA);
Answer to question 1:
Of course.
...
To answer your further questions:
Set of all the keys and its iterator,
Set<String> keys = mapOfMap.keySet();
Iterator<String> iterator = keys.iterator();
Look at http://code.google.com/p/synthfuljava/source/browse/trunk/common/org/synthful/util/HashTreeNode.java,
to see an example of what can be done with map of maps.
That tree hash node was written (poorly) in 2004 (and needs to have fluff like toStringBuffer removed), but it does adequately to illustrate an xpath addressable hash tree. I have another version for GWT with the fluff removed somewhere else.

storing hashMap in a hashMap

i am reading data from a text file and want to store HashMap in another HashMap..
HashMap<string,HashMap<string,value>>
how to store data and retrieve it?
any sample code will be appreciated...
thank u
Example:
Creating and populating the maps
Map<String, Map<String, Value>> outerMap = new HashMap<String, HashMap<String, Value>>();
Map<String, Value> innerMap = new HashMap<String, Value>();
innerMap.put("innerKey", new Value());
Storing a map
outerMap.put("key", innerMap);
Retrieving a map and its values
Map<String, Value> map = outerMap.get("key");
Value value = map.get("innerKey");
Creating two Simple Hashmaps: InnerMap and OuterMap
HashMap<String, HashMap<String, String>> outerMap = new HashMap<String, HashMap<String,String>>();
HashMap<String, String> innerMap = new HashMap<String, String>();
Populating the HashMaps
innerMap.put("InnerKey", "InnerValue");
outerMap.put("OuterKey", innerMap);
Retreiving values from HashMaps
String value = ((HashMap<String, String>)outerMap.get("OuterKey")).get("InnerKey").toString();
System.out.println("Retreived value is : " + value);
You get something that looks like a 2 dimensions HashMap, so to say. Which means you need 2 String to store a value, and also to retrieve one.
You could, for example write a class to wrap that complexity, like that (untested code):
public class HashMap2D<T> {
private HashMap<String,HashMap<String,T>> outerMap;
public HashMap2D() {
outerMap = new HashMap<String,HashMap<String,T>>();
}
public void addElement(String key1, String key2, T value) {
innerMap=outerMap.get(key1);
if (innerMap==null) {
innerMap = new HashMap<String,T>();
outerMap.put(key1,innerMap);
}
innerMap.put(key2,value);
}
public T getElement(String key1, String key2) {
Hashmap innerMap = outerMap.get(key1);
if (innerMap==null) {
return null;
}
return innerMap.get(key2);
}
}
If you want methods to process more than one data at a time, it's more complicated, but follows the same principles.
This will solve the same problem using one map (although, this does not directly answer your question) by flattening two nested maps into one big map, using a double-key.
public class Key2D{
private final String outer;
private final String inner;
public Key2D(String outer, String inner){
this.outer = outer;
this.inner = inner;
}
//include default implementations for
//Object.equals(Object) and Object.hashCode()
//Tip: If you're using Eclipse it can generate
//them for you.
}
Then just create one map with double-key:
Map<Key2D, Value> map = new HashMap<Key2D, Value>();
map.put(new Key2D("outerKey", "innerKey"), "Value");
map.get(new Key2D("outerKey", "innerKey")); // yields "Value"
This gives a shorter solution. Performance wise it's probably about the same. Memory performance is probably slightly better (just guessing, though).
HashMap in HashMap will cause problems in readability especially when it goes beyond two levels. I assume that when you read data from a text file you want to categorize the inputs from rows and columns which should be similar to multi-level categories or category within a category. If you can post the sample data and your intention, I could come up with a Custom class example.
public class Category {
private List<Category> subCategories;
private List<Item> items;
}
The above data structure will help you solve any level of nesting while categorizing data. This example is specific to a store items' classification.

Categories