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

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.

Related

Generic Classes term question based on the the data type

I understand with Generic classes in Java the class can have the parameter be almost of any data type. For example:
ArrayList<Integer> arrl1 = new ArrayList<>();
ArrayList<String> arrl2 = new ArrayList<>();
Here I am making one ArrayList to be of String type and the other to be of Integer type. In this case when referring to the two or separately, should I just treat them both as ArrayList objects or should both be treated as separately like one is an ArrayList object and the other is a String type Array List object. Which way is recommended to do, I do know due to type erasure both in compile time are just ArrayList.

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

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

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.

How can I add to unbounded lists? (Generics)

I am interested in doing the following:
Build a Map<SomeObject<?>, ?>. I thought to use 2 lists to add the keys and values:
List<SomeObject<?>> keys;
List<?> values;
But I don't know how to add objects in this list. Any ideas?
This is a continuation of this using #Ivan idea
Each entry could be different but key-value pair must be of same T
You can't do this using the field declaration alone.
What you can do is provide getter/ setters which perform the checking on a per entry basis.
final Map<Class, Object> classObjectMap = new LinkedHashMap<Class, Object>();
public <T> void putMap(Class<T> tClass, T t) {
classObjectMap.put(tClass, t);
}
#SuppressWarnings("unchecked")
public <T> T getMap(Class<T> tClass) {
return (T) classObjectMap.get(tClass);
}
The field itself doesn't provide the checking because you can't define the relationship on a per entry basis. With getters and setters you can ensure the types are correct and provided you only use those it will work as expected.
The type you have chosen means you can't add to them. I would make the type allow additions. You can use type erasure to work around the problem, but this is not ideal.
I did not say it doesn't work.I said I don't know how to build the lists which will contain different types of objects (mixed lists)
You can have a List<Object> which can contain any object. Or more simply just List.
Collections of unrelated mixed types is rarely a good idea. It usually means you are avoiding creating a custom class as you DVO or DTO.
You cannot add objects to for example a List which has a wildcard ? for its generic type.
That's because there's no way for the compiler to check if the object that you'd add is allowed for the actual type of the collection. For example:
// A List that should only contain strings
List<?> list = new List<String>();
// This is not allowed, because the compiler only knows that 'list'
// is a List<?>; so it can't be sure here that integers are allowed in the list
list.add(123);
See Which methods and fields are accessible/inaccessible through a reference variable of a wildcard parameterized type? in Angelika Langer's Java Generics FAQ for a longer explanation with an example.
basicly you can do that, but with little trick - since you know size of keys and values, you may use "toArray" method on map.keys() and map.values(). this will give you 2 arrays
class Key<T> {
}
Map<Key<?>, ?> map = new HashMap<Key<?>, Object>();
Key[] keyz = map.keySet().toArray(new Key[0]);
Object[] values = map.values().toArray(new Object[0]);
List<Key<?>> lstKey = Arrays.<Key<?>>asList(keyz);
List<?> lstVal = Arrays.asList(values);
arrays in Java are covariant, that makes it possible.

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