Related
This question already has answers here:
How to directly initialize a HashMap (in a literal way)?
(22 answers)
Is there a best practice for writing maps literal style in Java?
(10 answers)
Literal declaration of HashMap in Java [duplicate]
(2 answers)
Closed 7 months ago.
Is it possible to declare and initialize a Hashtable or Map, so we don't have to declare and initialize on two different steps?
// declare first
Hashtable<String, Integer> numbers = new Hashtable<String, Integer>(3);
// then initialize
numbers.put("one", 1);
numbers.put("two", 2);
numbers.put("three", 3);
In ruby and javascript, for example, there are literals to define those:
numbers = {
one: 1,
two: 2,
three: 3,
}
For Java 9 and beyond, you can make use of Map#of, as well as Map#ofEntries with Map#entry:
Map<String, String> example = Map.ofEntries(
Map.entry("1", "one"),
Map.entry("2", "two"),
Map.entry("3", "three"),
//...
);
For shorter literals (10 or less entries), you can use Map#of directly (albeit with a slightly confusing syntax of Key1, Value1, Key2, Value2, ...):
Map<String, String> example = Map.of("1", "one", "2", "two");
Prior to Java 9, this would typically only be needed for initializing constant Map objects, for which a static initializer block is also useful:
private static final Map<String, String> MY_CONSTANT;
static {
Map<String, String> setup = new HashMap<>();
setup.put("1", "one");
setup.put("2", "two");
setup.put("3", "three");
MY_CONSTANT = Collections.unmodifiableMap(setup);
}
This will allow you to create a constant Map while allowing you to modify the map before it is set.
As pointed out by #Pshemo, there are numerous reasons to avoid double-brace initialization, however the notable exception to the "rule" is typically in constants much like the above example (as numerous anonymous classes would not be made). However, it is still possible to work around the need for double-brace initialization even this case, so it is overall best to avoid if possible. The only case I can think of this not being possible is within the context of a constant within an enum class, where the double-brace init may truly be the only true way to make this work.
Firstly, you shouldn't use Hashtable class - it's legacy. If you need a general purpose implementation of the Map interface, use HashMap instead.
In case when you need to initialize a general purpose Map with a few entries, you can use one of the overloaded versions of Map.of() method which is available starting with Java 9. It allows providing up to 10 key-value pairs, if you need more you can use Map.ofEntries(), which takes a varargs of map entries. You can create a map entry using another Java 9 method Map.entry().
Example:
public static final Map<String, Integer> numbers =
Map.of("one", 1, "two", 2, "three", 3);
Note these maps are
1. Immutable, therefore it would be the right choice only if the data never change (or might change rarely, i.e. in case of very frequent reads and infrequent writes, and every write would require re-initializing the map).
2 So-called unmodifiable maps like MapN (which is an internal implementation used by Map.ofEntries() intended to store an arbitrary number of key-value pairs) are optimized in terms of Memory consumption, their underlying array occupies exactly as match space as match there are key-value pairs and no more, and retrieving a value from an unmodifiable map using get() might even perform slightly better (see the quote below) in comparison to a HashMap.
For more information you can refer to official documentation - Creating Immutable Lists, Sets, and Maps:
Use Cases
The common use case for the immutable methods is a collection that is
initialized from known values, and that never changes. Also consider
using these methods if your data changes infrequently.
For optimal performance, the immutable collections store a data set
that never changes. However, you may be able to take advantage of the
performance and space-saving benefits even if your data is subject to
change. These collections may provide better performance than the
mutable collections, even if your data changes occasionally.
If you have a large number of values, you may consider storing them in
a HashMap. If you are constantly adding and removing entries, then
this is a good choice. But, if you have a set of values that never
change, or rarely change, and you read from that set a lot, then the
immutable Map is a more efficient choice. If the data set is read
frequently, and the values change only rarely, then you may find that
the overall speed is faster, even when you include the performance
impact of destroying and rebuilding an immutable Map when a value
changes.
Also note that depending on the type of keys and the actual data (specifically on the number of collisions), an unmodifiable map might perform worse than a HashMap because contrary to HashMap unmodifiable map is incapable to store and reuse hashes of the keys and hence might perform more comparisons of keys using equals method. And in case of large number of collisions, unmodifiable map has no means to mitigate performance degradation, unlike HashMap which since would try to arrange nodes into a tree when the number of nodes in a bucket exceeds certain threshold.
Spiking of other alternatives doubly-brace initialization, which creates an instance of anonymous inner class, is indisputably a discouraged practice.
Static and instance initializer blocks have no downsides from the technical point of view, they allow you to keep the variables final if you need that. But some might argue that from the perspective of clean coding, initializer blocks are not very great.
Another possibility you might consider is to initialize a map inline using Stream API (for instance, when map-data can be expressed as a sequence that is easy to generate).
A similar way to appending new element to a vector like in C++ :-
myHashMap[myKey].push_back(newElement); //push newElement to the value vector directly
The only way i can think of in Java is to get the vector from hashmap. Append the new string to the vector and then set the key again with the new vector.
myValue = myHashMap.get(myKey);
/**Check if the key exists
**/
//If exists
myValue.add(newElement);
myHashmap.put(myKey, myValue);
Is the second approach as fast as the previous and if not is there any other approach? Thanks
You do not have to put back the vector back in the map as you are already modifying the vector when adding to it.
myHashMap[myKey].push_back(newElement);
is achieved by
myHashMap.get(myKey)
.add(newElement);
(assuming myHashMap.get(myKey) does not return a null).
You can use computeIfAbsent in the Map interface to construct a vector object for a key processed for the first time. This is more elegant and does not require a if block.
myHashMap.computeIfAbsent(key, k -> new Vector<>())
.add(newElement);
The function (k -> new Vector<>()) is only executed if the myHashMap does not have a mapping for the key key. The nice thing about this is it returns the vector value of key so that we can chain the add call on it.
Firstly, if you care about performance in Java, use ArrayList instead of Vector. As the javadoc says:
As of the Java 2 platform v1.2, [Vector] was retrofitted to implement the List interface, making it a member of the Java Collections Framework. Unlike the new collection implementations, Vector is synchronized. If a thread-safe implementation is not needed, it is recommended to use ArrayList in place of Vector.
So, assuming we are using Java 8 (and ArrayList), there are two translations for the C++ code.
Version #1. Works for Java 5+
HashMap<String, ArrayList<String>> myMap = new HashMap<>();
...
ArrayList<String> list = myMap.get(myKey);
if (list == null) {
list = new ArrayList<>();
myMap.put(myKey, list);
}
list.add(newElement);
Version #2. Works for Java 8+
HashMap<String, ArrayList<String>> myMap = new HashMap<>();
...
myMap.computeIfAbsent(key, k -> ArrayList<>()).add(newElement);
Which will be faster? You would need to test it to be sure, but I think that the second version should be a bit faster because it avoids the second hashmap lookup in the put call.
And 1 line of code is neater than 6 lines. (YMMV for readability. It depends on the person reading the code, and how familiar they are with Java 8+ language features and APIs.)
You can do this in the same way in java.
myHashMap.get(key).add(newValue)
Because in the hashmap the reference of list (or you can say it vector) is stored as value. So modifying the content of List will not influence the reference. You can imagine this reference likes 64bits address of a vector in c++.
What's the difference between using a typed vs. non-typedArrayList in Java?
For example, Using an ArrayList of CustomObject:
Typed:
ArrayList<CustomObject> typedArray = new ArrayList<>();
typedArray.add(new CustomObject);
or non-typed:
ArrayList<> nonTypedArray = new ArrayList<>();
nonTypedArray.add(new CustomObject);
Is there any situation where the latter is preferred? Is there any difference when the ArrayList is holding different datatypes, e.g. an ArrayList of String, Int, etc.?
In the Second Approach, it is not mandatory to add only CustomObject whereas it is in 1st Approach, otherwise, you will get Compilation Error.
ArrayList<CustomObject> typedArray = new ArrayList<>();
typedArray.add(new CustomObject());
This approach is generally preferable as there are no chances of having Class Cast Exception but in second approach there are high chances of that !!
JavaDocs explains it beautifully : Why to prefer Generics
Stronger type checks at compile time.
Elimination of casts.
Enabling programmers to implement generic algorithms.
It's never preferable to use the latter option. I don't think that is even possible. I think you meant:
ArrayList nonTypedArray = new ArrayList();
This syntax is left over from Java 1.4 and earlier. It still compiles for the purposes of backwards compatibility.
Generics was introduced in Java 1.5 which allowed you to specify the types between angled brackets.
It is always preferable to use generics because it is more type-safe.
That is, if you specify
ArrayList<String> typedArray = new ArrayList<String>();
Then you cannot accidentally add an integer to this array list; if you tried to add an integer, the program would not compile.
Of course, Generics ensures type safety at compile time. At runtime ArrayList<String> typedArray = new ArrayList<String>(); becomes ArrayList typedArray = new ArrayList();. This is to maintain backwards compatibility.
What's the difference between using a typed vs. non-typed ArrayList in
Java?
A typed/generic ArrayList is a collection of objects in which the "type" of the object is defined in angled brackets. Generics were introduced in Java 5 to create type-safe collections.
Before Generics the collection was called untyped/raw type collection because there was no way to specify the compiler the type of the collection being created.
The difference between both is to detect type-safe operations at compile time.
In both of your cases, you are adding object(s) of type 'CustomObject' to the ArrayList. There will be no issue while adding elements in the list, as both lists will consider them as typed objects.
Typed:
ArrayList<CustomObject> typedArray = new ArrayList<CustomObject>();
typedArray.add(new CustomObject);
Untyped:
ArrayList<> nonTypedArray = new ArrayList<>();
nonTypedArray.add(new CustomObject);
Is there any situation where the latter is preferred?
I don't think so. As generics are recommended to be used while creating a list to ensure type-safe operations.
Is there any difference when the ArrayList is holding different
datatypes, e.g. an ArrayList of String, Int, etc.?
Surely, there is a reasonable difference. For an untyped list, you will need to add type-cast while fetching elements from a list. As there is a possibility of the compiler throwing a ClassCastException at runtime due to different types of elements.
In runtime, there is absolutely no difference, however in compilation time, using type parameters can save you from a plethora of errors, so it is always preferable to use generics properly.
The only case where raw types are used reasonably is in legacy applications, but even in this case, you try to use typed parameters if you can.
The use of type simplifies your coding removing the need of casting and also stores your data efficiently
https://docs.oracle.com/javase/tutorial/java/generics/why.html
Yeah, I know this is an old post. But I wanted to share an instance where an untyped ArrayList is useful: when you're writing a function that supposed to act on arbitrary element types. For example, suppose you want to make a generic shuffle function that knows how to shuffle an array. Like so:
ArrayList<Die> diceRolls = getGetPossibleDiceRolls();
ArrayList<Card> cardDeck = getPossibleCards();
ArrayList<GirlToDate> blackbook = getBlackbook();
shuffle(diceRolls);
shuffle(cardDeck);
shuffle(blackbook);
.
.
void shuffle(ArrayList array) {
int size = array.size();
for (int i=0; i<size; ++i) {
int r = random.nextInt(size - i) + i;
// Swap
Object t = array.get(i);
array.set(i, array.get(r));
array.set(r, t);
}
}
Some might argue "yeah, but the proper way to do this is to create an interface or subclass of something like a Shuffleable type..." But really?
In Java 1.7 and upwards you should normally use the constructor like this:
ArrayList<MyObject> list = new ArrayList<>();
or else for a more general List object:
List<MyObject> list = new ArrayList<>();
Observe that you only specify the type <MyObject> once, not twice. This makes your code easier to maintain. The <> causes the constructor to return an ArrayList which is already typed to match the field/variable to which it is being assigned - so that no cast will be required in the calling code.
Do not use new ArrayList() as the constructor. This returns an untyped ArrayList which then has to be cast to a type to match the field/variable to which it is being assigned. This means unnecessary type checking and casting and so generally reduces performance.
I can declare an array of maps using generics to specify the map type:
private Map<String, Integer>[] myMaps;
However, I can't figure out how to instantiate it properly:
myMaps = new HashMap<String, Integer>[count]; // gives "generic array creation" error
myMaps = new HashMap[count]; // gives an "unchecked or unsafe operation" warning
myMaps = (Map<String, Integer>[])new HashMap[count]; // also gives warning
How can I instantiate this array of maps without getting a compiler error or warning?
Update:
Thank you all for your replies. I ended up going with the List suggestion.
Not strictly an answer to your question, but have you considered using a List instead?
List<Map<String,Integer>> maps = new ArrayList<Map<String,Integer>>();
...
maps.add(new HashMap<String,Integer>());
seems to work just fine.
See Java theory and practice: Generics gotchas for a detailed explanation of why mixing arrays with generics is discouraged.
Update:
As mentioned by Drew in the comments, it might be even better to use the Collection interface instead of List. This might come in handy if you ever need to change to a Set, or one of the other subinterfaces of Collection. Example code:
Collection<Map<String,Integer>> maps = new HashSet<Map<String,Integer>>();
...
maps.add(new HashMap<String,Integer>());
From this starting point, you'd only need to change HashSet to ArrayList, PriorityQueue, or any other class that implements Collection.
You can't safely create a generic array. Effective Java 2nd Edition goes into the details in the chapter on Generics. Start at the last paragraph of page 119:
Why is it illegal to create a generic
array? Because it isn’t typesafe. If
it were legal, casts generated by the
compiler in an otherwise correct
program could fail at runtime with a
ClassCastException. This would violate
the fundamental guarantee provided by
the generic type system.
To make this more concrete, consider
the following code fragment:
// Why generic array creation is illegal - won't compile!
List<String>[] stringLists = new List<String>[1]; // (1)
List<Integer> intList = Arrays.asList(42); // (2)
Object[] objects = stringLists; // (3)
objects[0] = intList; // (4)
String s = stringLists[0].get(0); // (5)
Let’s pretend that line 1, which
creates a generic array, is legal.
Line 2 creates and initializes a
List<Integer> containing a single
element. Line 3 stores the
List<String> array into an Object
array variable, which is legal because
arrays are covariant. Line 4 stores
the List<Integer> into the sole
element of the Object array, which
succeeds because generics are
implemented by erasure: the runtime
type of a List<Integer> instance is
simply List, and the runtime type of a
List<String>[] instance is List[], so
this assignment doesn’t generate an
ArrayStoreException. Now we’re in
trouble. We’ve stored a List<Integer>
instance into an array that is
declared to hold only List<String>
instances. In line 5, we retrieve the
sole element from the sole list in
this array. The compiler automatically
casts the retrieved element to String,
but it’s an Integer, so we get a
ClassCastException at runtime. In
order to prevent this from happening,
line 1 (which creates a generic array)
generates a compile-time error.
Because arrays and generics don't combine well (as well as other reasons), it's generally better to use Collection objects (in particular List objects) rather than arrays.
In general it is not a good idea to mix generics and arrays in Java, better use an ArrayList.
If you must use an array, the best way to handle this is to put the array creation (your example 2 or 3) in a separate method and annotate it with #SuppressWarnings("unchecked").
You can create generic array of map
Create list of map.
List<Map<String, ?>> myData = new ArrayList<Map<String, ?>>();
Initialize array.
Map<String,?>[]myDataArray=new HashMap[myData .size()];
Populate data in array from list.
myDataArray=myData.toArray(myDataArry);
Short answer appears to be that you really just can't.
See the following for a blog about it.
http://www.bloggingaboutjava.org/2006/01/java-generics-quirks/
One of the comments to the blog states that:
Actually, the engineers made the creation of such an Array illegal. So the creation of an array from generic Class fails. The Collection.toArray method followed by a Cast to the Array works at compile time.
This solves not the problem, that the ArrayStoreCheck can’t be done during Runtime, but you can create an Array of generics in this way.
As suggested by Bill the Lizard, you probably are better off using a
List<Map<String,Integer>>
I know its a bit late to reply but I found this workaround helpful for my case...Hope it helps!
Use an array of HashMap to store HashMaps..
public static void main(String[] args) {
HashMap[] arr = new HashMap[1];//creating an array of size one..just for sake of example
HashMap<String, String> arrMap = new HashMap<String, String>();
//use loops to store desired key-value pairs into the HashMap which will be stored inside the array
arrMap.put("ABC", "Name");
//use loop to store your desired hashMap into the array at a particular index
arr[0] = arrMap;
//desired manipulation of the stored array.
System.out.println(arr[0]);
}
myMaps = new HashMap<String, Integer>[10]();
So that's Wrong
Why not make a List of Maps instead of trying to make an array?
List<Map<String, Integer>> mymaps = new ArrayList<Map<String, Integer>>(count);
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