Memory assignement for Map<String,List<String>> - java

When we do Map<String,List<String>> = new HashMap<String, List<String>>();
it creates an empty map but is the List inside the map empty as well or is it a null value?

To a certain degree, this depends on the collection type you are using. A hashmap or hashset will not allocate any space for objects that will potentially be added later on. So you only carry the "cost" for exactly that one map or set object when creating it.
Whereas for ArrayList, that is different - they are created using an initial capacity (10 by default); meaning that creating an ArrayList<String> will allocate for an array of strings (String[10] in that sense). So, HashMap<String, List<String>> is "cheaper" than List<Map<Whatever, NotOfInterest>>.
On the other hand: this is really not something to worry about. Unless you are working in "embedded computing" (or you are dealing with millions of objects all the time), you should much more worry about good OO designs instead of memory (or performance) cost of java collections.

Your code:
Map<String,List<String>> = new HashMap<String, List<String>>();
pertains only to the instantiation of a parameterized HashMap. You are using generics to enforce generic types, which states that the TYPE for key must be a String and the TYPE value must be a List<String>. There is no List<String> in memory until you begin adding separately created List<String> objects into to your map. This would look like this:
Map<String, List<String>> myMap = new HashMap<>();//BTW, You only need to parameterize the object declaration since Java 7
List<String> names = new ArrayList<String>();
names.add("Betty");
names.add("Bob");
names.add("Jessica");
names.add("Jim");
myMap.put("names", names);//Where "names" is your key and names is your value.
You can proceed to continue adding more lists to your map from there.

Accepted answer: When you instantiate a collection, it is empty. Any initial capacity it has are of null values, so there are no Lists in this case. – Zircon

Related

Initializing an array of pairs in Java

I would like to initialize an Array of pairs but my way is not fully correct.
Here how I first wrote it:
Pair<String, Integer>[] pair = new Pair[5];
It is accepted and it works but there is still the following warning:
"Unchecked assignment: 'android.util.Pair[]' to 'android.util.Pair<Java.lang.String, Java.lang.Integer>[]'...
I already tried to do like this:
Pair<String, Integer>[] pair = new Pair<String, Integer>[5];
but it doesn't work.
It is because of the nature of generics.
My suggestion is to drop the idea of using arrays directly, and use a List<Pair<String, Integer>> instead. Under the hood, it uses an array anyway, but a List is more flexible.
List<Pair<String, Integer>> list = new ArrayList<Pair<String, Integer>>();
// You don't have to know its size on creation, it may resize dynamically
or shorter:
List<Pair<String, Integer>> list = new ArrayList<>();
You can then retrieve its elements using list.get(index) whereas you would use list[index] with an array.
You can not create an array of generified type, in this case Pair. That's why your first solution works, because you did not specify the concrete type of Pair.
Technically, you can create an array, Generic arrays in Java, but it's not reccomended.

How to initiate multidimensional arraylist with different objects?

I'm having trouble trying to initiate an arraylist in which the first column I want to be a string, and the second column be a custom object.
For example column [0] be String, and column[1] be an Integer. Convention attempts of creating a multidimensional arraylist as in those used by int[][] or String[][] don't seem to work :( I would welcome any help. At this point I don't think it's something java allows. I can make it work for just one type of object but it's not what I want. Thanks!
Do you need an arraylist? You could create a Map<String, Object> or Map<String, Integer> or whatever you need..
Sure it does, but you weaken/eliminate type-checking:
Map myMap<String>, Integer> myData = new HashMap<String, Integer>();
Now your list of strings can be retrieved by myMap.keySet() and values can be retrieved by myMap.values(). Each of these return a Set, which you can easily convert to a List using the following code:
List<String> strings = new ArrayList<String>(myMap.keySet()); // get your strings
List<Integer> numbers = new ArrayList<Integer>(myMap.values(); // get your numbers
Good luck and if you should run into problems, do leave a comment.
Arrays are geared towards one specific type of thing - be they Object or String or int. Despite the fact that you're adding multiple dimensions to them, they still only hold one type of information.
What you would rather have is a mapping between two objects. This allows you to do the following:
Associate any key to a particular value
Eliminate duplicate key entries
Be much easier to access instead of array indexing
Here's an example. Say your custom object is a Cat, and you want to map the name of the owner to a particular Cat. You create a new instance of a Map.
Map<String, Cat> catOwners = new HashMap<>();
You can then put elements into it...
catOwners.put("Jamie", new Cat("Tycho"));
...and retrieve them with relative ease.
Cat currentCat = catOwners.get("Jamie"); // gets Jamie's cat
if you really want to, you can even iterate over them using the Map.Entry object provided with all Maps:
for(Map.Entry<String, Cat> element : catOwners.entrySet()) {
System.out.println(element.getKey()
+ " owns " + element.getValue().getName());
}
What you can do is use the generic Object type, and cast accordingly.

What do the <>'s mean in Java declarations and instantiations?

I am new to java and have a question
myBooks = new ArrayList<HashMap<String,Object>>();
What is HashMap and what does it mean when we use < > for ArrayList class?
Both HashMap and ArrayList can be considered as array in PHP. ArrayList is indexed by number, and HashMap is collection of key value pairs - PHP does not differentiate those two situations.
This particular declaration says that there is an ArrayList (number indexed array) and all its element are of type HashMap. For each HashMap, which is a collection of key/value pairs, the keys are of type String, and values are of type Object.
It indicates generic type in Java. For instance, if you're using an ArrayList as follows
myBooks = new ArrayList<String>();
means that what is being stored into the ArrayList myBook will be of type String available in Java.
In the following statement
myBooks = new ArrayList<HashMap<String,Object>>();
The ArrayList is holding a HasMap with keys of type String and values of type Objects.
Similarly, you can make use of Collection, List, HashTable etc with generic types and should always be used with generic types because they can hold any kind of values.
such as
Collection<String> c=new ArrayList<String>();
List<String>list=new ArrayList<String>();
Hashtable<String, String> h = new Hashtable<String, String>();
You could have simply defined them without genetic types as follows.
Collection c=new ArrayList();
List list=new ArrayList();
Hashtable h=new Hashtable();
The compiler will not complain at all in this situation but its always preferable to use generic with them.
This is an example of Java generics.
A data structure like List or Map or Set can hold any kind of object. When you use generics, you tell the compiler exactly what type of object the data structure is holding.
In your case, you've got a List of Maps. The Map has String keys and Object values.
All of the above answers are great.
In addition, though, I would like to point out that you should also read up on Java Type Erasure to understand the difference between the compile-time and run-time behaviors of Generics.
You will save yourself a lot of pain by understanding type erasure correctly.

HashMap Copy behavior I can't figure out

I am having trouble getting a separate copy of my HashMaps. By that I mean, once I have made a copy of the original, making a change to one does not change the other.
I have two HashMaps in this format:
HashMap<String, List<String> one = new HashMap<String, List<String>();
HashMap<String, List<String> two = new HashMap<String, List<String>();
I call the following function below (getTabSetDifferences) passing in one and two, as expected if there are some differences, those values will be removed from the HashMap
and it'll be different than before it was passed in for the test.
I want them to remain unchanged, so tried passsing in:
getTabSetDifferences((HashMap)one.clone(), (HashMap)two.clone())
This still changed the originals, so i created two more hashmaps in the same format, and cloned one and two to them, I used the new hashmaps to pass
in, and the original was still changed.
I then tried:
HashMap<String, List<String>> holdOne = new HashMap<String, List<String>>();
holdOne.putAll(one);
HashMap<String, List<String>> Holdtwo = new HashMap<String, List<String>>();
holdTwo.putAll(two);
Now I can do something like:
holdTwo.remove(key);
and the original is not changed, but if i call the method with holdOne and holdTwo it still changes the original one and two hashmaps, shouldn't they remain?
The method is working, and finding the differences i want, and is returned. But I still need the original two hashmaps to be as they were, but no matter which
way I call, what ever changes are made to holdOne and holdTwo changes the originals. Is that the expected behavior? If so, what is the proper way
to get a copy of a hashmap that is not tied to it.
getTabSetDifferences(holdOne, holdTwo);
public HashMap<String, List<String>> getTabSetDifferences(HashMap<String, List<String>> hmMain, HashMap<String, List<String>> hmSecond) {
HashMap<String, List<String>> hmDifferences = new HashMap<String, List<String>>();
for (Map.Entry<String, List<String>> entry : hmMain.entrySet()) {
if(hmSecond.containsKey(entry.getKey())) {
entry.getValue().removeAll(hmSecond.get(entry.getKey()));
if (entry.getValue().size() > 0)
hmDifferences.put(entry.getKey(), entry.getValue());
}
else {
hmDifferences.put(entry.getKey(), entry.getValue());
}
}
return hmDifferences;
}
The clone method doesn't do a deep copy.
You have 2 options.
create a deep copy method.
Use one of the Map implementations from the java.util.concurrent package like copyOnWrite
I suspect you are only copying the keys/values. This will not create copies of the lists.
Perhaps Guava's MultiMap is what you want?
If you copy the list as a list (i.e. copy it at list scope, rather than some lower level implementation), then the pointer behavior will be seen.... However if you copy from one list into a new list, then those string objects are independant.
Java's clone method should not be use in expectation that it will return distinct , deep copies of an object - immutability is not a central concept to the way clone works.
I agree with the above comment : either use a multimap in a library like guava, or google collections, or simply be very careful about your copying, and only copy at the primitive levels, (don't ever copy a collection and expect it to be independent) unless you've tested this explicitly .

Java array of Hashtables

I need an array of Hashtables in a program that is storing all words from a given set of documents.
Index 1 of the array holds a hashtable of String -> Double which stores a word, and its count for document 1 (array index 100 = document number 100's hashtable).
I dont need help using this data structure, just in creating it.
I declare the Hashtable Array as follows:
Hashtable<String,Double>[] h1 = new Hashtable<String,Double>[];
... but this does not compile.
(NOTE: The Double is necessary rather than an Integer in the above declaration for later usage.)
QUESTION:
How do you create an array of hashtables which stores String->Double ???
Any suggestions appreciated guys....
... but this does not compile.
That's because the array has no name, new expects a number of elements and you can't just allocate an array of generics. Prefer a List instead:
List<Hashtable<String,Double>> wordCountPerDoc
= new ArrayList<Hashtable<String,Double>>();
just use
#SuppressWarnings("unchecked")
Hashtable<String,Double>[] h = (Hashtable<String,Double>[])new Hashtable<?,?>[10];
h[0] = new Hashtable<String, Double>();
why don't you use a Map<Integer, Map<String, Double> > ?
this way you don't waste space for non-existing documents, and still get O(1) retrieval.
you can create like this.
Hashtable<String,Double>[] arr = new Hashtable[10];
Two things: you can't declare an array with the parameterized types like that; you have to imply declare it a new Hashtable[]. And you need to give the array a length.
Mixing arrays and Collections, although possible, tends to be confusing and lead to problems in my experience; also HashMap is generally preferred to Hashtable. So I would tend to prefer a List<Map<String, Double>> for this application.
The reasons why this is an error are covered in Angelika Langer's Generics FAQ: Can I create an array whose component type is a concrete parameterized type?
Can I create an array whose component type is a concrete parameterized type?
No, because it is not type-safe.
Arrays are covariant, which means that
an array of supertype references is a
supertype of an array of subtype
references. That is, Object[] is a
supertype of String[] and a string
array can be accessed through a
reference variable of type Object[].
Arrays and generics can have odd interactions (largely due to implementation compromises to support compatibility). You may be better off (as larsmans suggested) looking at a suitable collection type such as a List of Maps.
An array seems to be an unusual choice of structure here. Perhaps you should consider storing your hashtables in a List. It will dynamically resize for you if you don't know how many document you will have ahead of time. If you use an ArrayList, you will still have constant-time reads of random indeces (like an array.) I think it's much simpler than using an array, and you still get the generic type checking. If you choose a List, you syntax becomes:
List<Map<String,Double>> documentWordCounts = new ArrayList<Map<String,Double>>();
Or choose a LinkedList depending on what kind of read/write pattern you want.
For fixed size array:
Hashtable<String,Double>[] h1 = new Hashtable[]{new Hashtable< String,Double>(),new Hashtable< String,Double>(),new Hashtable< String,Double>()};

Categories

Resources