What is the difference between the following?
new HashMap(); vs new HashMap<Integer, String>();?
I've never used the former or seen it but is there any differences I should know?
First one doesnt know what type of data hashmap has. You can have any type of object in this map. Second one specifies what is key and value types for this map. You can only insert those types into map. This approach is called generics.
Following statement will creates a map whose key-value types are raw. (java.lang.Object).
HashMap map=new HashMap();
In second statement, you are specifying type of Key and Value (Read Java Generics) .
HashMap<Integer,String> map=new HashMap<Integer,String>();
It should be new Hashmap<Integer, String>().
The first case will use Object type for keys as well as values and will return Object instances when you retrieve them. In the second case, you are specifying that the keys should be of Integer type and the values are of String type. So, you should add accordingly and when you retrieve, you'll get String object for values and Integer object for keys and you will not need a cast as in the previous case.
P.S. I think the reason you should use Integer and not int is that the type used should be "nullable" if some method needs to return null. int is not nullable.
Related
I am doing a small project of reading delimited files into columns and displays them. Now i want a column class that is basically a wrapper arround a HashMap, but there is one problem, I don't know the second generic data type until the Columns constructor is called out. The constructor takes an enum with data type argument, like the below:
private enum DataTypes{
NONE, INTEGER, STRING, DATE
}
what I have in mind is create the Column class field as a Collection, then I could initialize it when the constructor is called, like the below:
private class Column {
Collection values;
public Column(DataTypes type){
determineType(type);
}
private void determineType(DataTypes type){
switch(type){
case NONE: this.values = (Collection) new HashMap<Integer, StringBuilder>();
break;
case INTEGER: this.values = (Collection) new HashMap<Integer, Integer>();
break;
case STRING: this.values = (Collection) new HashMap<Integer, StringBuilder>();
break;
case DATE: this.values = (Collection) new HashMap<Integer, Date>();
break;
}
}
}
My question is why do I have to cast it to the collection type (as eclipse force me) and does it mean that I cannot use any methods of HashMap?
Also is there a better aproach or maybe design pattern for a situation like that, and what could be improved? Is there anything that could go wrong with this apraoch later on like for example when adding a value as I feel that I would need to have an overloaded function for each data type to add a value.
Sorry for such a long list of questions, but I just got little experience in actuall projects and design and need a "little" guidance. (University projects are small with variables like a,b,c,x,y etc)
Thanks:)
EDIT
After a whole day of searching and asking this very badly written question I have found the Strategy design pattern is what I need, i will post the code later.
HashMap doesn't extend Collection. So you can't assign a HashMap to a variable of type Collection.
Eclipse doesn't force you to cast. You chose to accept one of the ways it suggested to make that code compile, but that doesn't mean the code is correct. It will fail at runtime, since HashMap is not a Collection.
I have a hard time understanding what this Column should represent. What would be the keys and the values of that HashMap? And, if what you actually want is not a HashMap, but a Collection, what woud be the values of the Collection?
In any case, since all the types you want to store in the Collection/Map have a single ancestor class (Object), you should probably use that as the type of your Collection/Map. You should also avoir storing StringBuilder. Use String instead.
You can declare your HashMap with the wildcard operator.
private class Column {
HashMap<?,?> values;
Then you can initilize the Map as normal
case INTEGER: this.values = new HashMap<Integer, Integer>();
Only problem is that you have to cast your HashMap to HashMap<Integer, Integer> every time you put something to it.
HashMap is not a Collection nor does it inherit from Collection
The class definition of HashMap is:
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable
Therefore, HashMap is a Map and implement the Map interface, not Collection
Because all of your case statements are instantiating HashMap, it makes sense to change the declaration of values to a Map instead of `Collection:
Map values;
In addition, because all of your case statements declare HashMap with the key as type Integer, but the values as varying types, you can declare the values Map accordingly.
Map<Integer, ?> values;
The reason Eclipse was suggesting you cast your HashMap to Collection is because the Maps are not descendants of Collection and therefore the only way to satisfy the compiler would be to cast them, which would still end up with a runtime error, since they are not collections.
By making the change to the declaration of values to type Map, you will not only no longer need to cast, but will eliminate your runtime errors.
how to declare variable like this-- ArrayList LinkedhashMap.
Map<String, ArrayList<LinkedHashMap<KeyType, ValueType>> maps;
KeyType and ValueType are placeholders, I don't know the real types. And the real declaration should use interfaces. But that's the closest to answer your question.
(The better declaration:
Map<String, List<Map<KeyType, ValueType>> maps;
We map lists of maps to string values. That's the explanation for this datastructure
)
Well if you are using Java 1.5 or greater , you can make use of Generics
//This approach is type safe.
List<LinkedHashMap<KeyType,ValueType>> myListOfMaps = ArrayList<LinkedHashMap<KeyType, ValueType>>();
for Java less that 1.5 use normal Arraylist.
List myListOfMaps = new ArrayList (); //But with this approach its not type safe ,
//because any object type can be inserted
Now to create a Map of ListsofMaps
Map<String, List<Map<KeyType, ValueType>> maps = new HashMap <String, List<Map<KeyType, ValueType>>();
maps.put("rows",myListOfMaps );
This link will give you Why Use Generics ?
Check this Generic tutorial for more info
I store in a HashMap 3 types of object.
HashMap<String, ArrayList<Car>>
['Lorry', [list of lorries]]
['Sport', [list of sport's cars]]
The HashMap string key keeps the type of object (a subclass of Car), the second element stores in array the objects that have e.g. attributes like: ID, date etc.
The four main things I have to do are:
Check if certain ID exist in HashMap when there is no information provided about its type
Print elements of certain ID given the type.
Print all elements of certain type
Print all element from the collection (of different types) if certain attribute that each object has assigned has a Boolean value of e.g. "true";
Is the HashMap the proper structure? I find it problematic if it comes to the first point. It seems like I will have to traverse the whole collection and if so what other collection is better for such requirements?
The basic approach is sound, however since you only want to store each instance once, a Set is a better choice than a List for the map entry value:
Map<String, Set<Car>> typeCache = new HashMap<String, HashSet<Car>>();
The contains() method of HashSet is very fast indeed, so finding if your map contains a particular instance in it values is not going to cost much.
Using two maps would probably be better though - once for each type of lookup, so also use:
Map<String, Object> idCache = new HashMap<String, Object>();
A HashMap is the right data structure for the job, but in your case you might consider using two HashMaps: One holding the relation 'Car Type' -> 'Cars of that Type', and a second one for the relation 'ID' -> 'Car with that ID'.
I have a Hashtable which has a key of String and the value as String, but I've reached a point in my project where I need to be able to store multiple different data types. For example, I'm going to need to store int, String, Date, etc, all in one Hashtable.
HashTable or any Collection Map can handle this, except for int and other primitive types: you can't store primitive types, only Object references. int will need to be wrapped as a Integer object.
Map<String, Object> map = new HashMap<String, Object>()
This gives you a map with keys of type String and values of type Object, which basically means any descendant of type Object (Date, Integer, String etc.). Other answers correctly point to the fact that instead of using primitives such as int, boolean it is required to use their counterparts Integer, Boolean etc.
The return type of get operation on such map is Object. Thus, it is developer's responsibility to handle type information correctly.
A good answer to the question as to what is the difference between Hashtable and HashMap is provided here.
You can have it store the general data type Object, though that will not allow primitive data types.
While this is possible, it's generally not a good idea. More often than not this leads to type casting exceptions and problems.
The HashTable can be set to store generic Objects as opposed to specific class types, however the type conversion when retrieving them does not happen automatically.
In order to get the object back out of the collection, some form of type checking routines will have to be developed.
You're better off creating a separate collection for each class type you want to store.
PS: I would also recommend using a HashMap instead of HashTable. HashTable has been deprecated.
Change your HashTable to Hashtable<String, Object> and when you want to store an int you need to cast it first(or use autocast) to an Integer. After getting your value from the table you can determ your type by if(value instanceof String) and so on for any type.
So I have two questions about HashMaps in Java:
What is the correct way to initialize a HashMap? I think it might be best in my situation to use:
HashMap x = new HashMap();
But Eclipse keeps suggesting that I use:
HashMap<something, something> map = new HashMap();
Which is better?
Can a HashMap hold different types of objects/data types as values? For example, would this work and be OK:
map.put("one", 1);
map.put("two", {1, 2});
map.put("three", "hello");
In the first put(), I want an int as a value, in the second an int[], and third a string. Is this okay to do in Java with HashMaps? Also, is it okay to store a HashMap as a value within a HashMap?
It really depends on what kind of type safety you need. The non-generic way of doing it is best done as:
Map x = new HashMap();
Note that x is typed as a Map. this makes it much easier to change implementations (to a TreeMap or a LinkedHashMap) in the future.
You can use generics to ensure a certain level of type safety:
Map<String, Object> x = new HashMap<String, Object>();
In Java 7 and later you can do
Map<String, Object> x = new HashMap<>();
The above, while more verbose, avoids compiler warnings. In this case the content of the HashMap can be any Object, so that can be Integer, int[], etc. which is what you are doing.
If you are still using Java 6, Guava Libraries (although it is easy enough to do yourself) has a method called newHashMap() which avoids the need to duplicate the generic typing information when you do a new. It infers the type from the variable declaration (this is a Java feature not available on constructors prior to Java 7).
By the way, when you add an int or other primitive, Java is autoboxing it. That means that the code is equivalent to:
x.put("one", Integer.valueOf(1));
You can certainly put a HashMap as a value in another HashMap, but I think there are issues if you do it recursively (that is put the HashMap as a value in itself).
This is a change made with Java 1.5. What you list first is the old way, the second is the new way.
By using HashMap you can do things like:
HashMap<String, Doohickey> ourMap = new HashMap<String, Doohickey>();
....
Doohickey result = ourMap.get("bob");
If you didn't have the types on the map, you'd have to do this:
Doohickey result = (Doohickey) ourMap.get("bob");
It's really very useful. It helps you catch bugs and avoid writing all sorts of extra casts. It was one of my favorite features of 1.5 (and newer).
You can still put multiple things in the map, just specify it as Map, then you can put any object in (a String, another Map, and Integer, and three MyObjects if you are so inclined).
Eclipse is recommending that you declare the type of the HashMap because that enforces some type safety. Of course, it sounds like you're trying to avoid type safety from your second part.
If you want to do the latter, try declaring map as HashMap<String,Object>.
The way you're writing it is equivalent to
HashMap<Object, Object> map = new HashMap<Object, Object>();
What goes inside the brackets is you communicating to the compiler what you're going to put in the HashMap so that it can do error checking for you. If Object, Object is what you actually want (probably not) you should explicitly declare it. In general you should be as explicit as you can with the declaration to facilitate error checking by the compiler. What you've described should probably be declared like this:
HashMap<String, Object> map = new HashMap<String, Object>();
That way you at least declare that your keys are going to be strings, but your values can be anything. Just remember to use a cast when you get a value back out.
The 2nd one is using generics which came in with Java 1.5. It will reduce the number of casts in your code & can help you catch errors at compiletime instead of runtime. That said, it depends on what you are coding. A quick & dirty map to hold a few objects of various types doesn't need generics. But if the map is holding objects all descending from a type other than Object, it can be worth it.
The prior poster is incorrect about the array in a map. An array is actually an object, so it is a valid value.
Map<String,Object> map = new HashMap<String,Object>();
map.put("one",1); // autoboxed to an object
map.put("two", new int[]{1,2} ); // array of ints is an object
map.put("three","hello"); // string is an object
Also, since HashMap is an object, it can also be a value in a HashMap.
A HashMap can hold any object as a value, even if it is another HashMap. Eclipse is suggesting that you declare the types because that is the recommended practice for Collections. under Java 5. You are free to ignore Eclipse's suggestions.
Under Java 5, an int (or any primitive type) will be autoboxed into an Integer (or other corresponding type) when you add it to a collection. Be careful with this though, as there are some catches to using autoboxing.
Eclipse is suggesting you to define generic type so that you can have type safety. You can write
Map m = new HashMap();
which does not ensure type safety but following will ensure type safety
Map<Object,Object> = new HashMap<Object,Object>();
The Object can be any type such as String, Integer etc.
Map.of literals
As of Java 9, there is yet another way to instantiate a Map. You can create an unmodifiable map from zero, one, or several pairs of objects in a single-line of code. This is quite convenient in many situations.
For an empty Map that cannot be modified, call Map.of(). Why would you want an empty set that cannot be changed? One common case is to avoid returning a NULL where you have no valid content.
For a single key-value pair, call Map.of( myKey , myValue ). For example, Map.of( "favorite_color" , "purple" ).
For multiple key-value pairs, use a series of key-value pairs. ``Map.of( "favorite_foreground_color" , "purple" , "favorite_background_color" , "cream" )`.
If those pairs are difficult to read, you may want to use Map.of and pass Map.Entry objects.
Note that we get back an object of the Map interface. We do not know the underlying concrete class used to make our object. Indeed, the Java team is free to used different concrete classes for different data, or to vary the class in future releases of Java.
The rules discussed in other Answers still apply here, with regard to type-safety. You declare your intended types, and your passed objects must comply. If you want values of various types, use Object.
Map< String , Color > preferences = Map.of( "favorite_color" , Color.BLUE ) ;
In answer to your second question: Yes a HashMap can hold different types of objects. Whether that's a good idea or not depends on the problem you're trying to solve.
That said, your example won't work. The int value is not an Object. You have to use the Integer wrapper class to store an int value in a HashMap