Map<String, ArrayList<Pair<String, Integer>>> k = new Map<String, ArrayList<Pair<String, Integer>>>();
This line is in my code. I'd like to instantiate a Map that contains a String then an ArrayList of Pairs of Strings and Integers.
Pair is a class that I wrote that is in my package.
I get "Cannot Instantiate the type Map>>();
Why not? Seems reasonable to me...
The built-in Map is an interface, which cannot be instantiated. You can choose between lots of implementing concrete classes on the right side of your assignment, such as:
ConcurrentHashMap
HashMap
LinkedHashMap
TreeMap
and many others. The Javadocs for Map lists many direct concrete implementations.
Interfaces cant be intantiated
You need to use some concrete class implementing the interface
Try something like this
Map<String, ArrayList<Pair<String, Integer>>> k = new HashMap<String, ArrayList<Pair<String, Integer>>>();
Related
I'm trying Kotlin and I've encountered a small problem that I can't resolve.
When I have the following construction I can put elements into the map:
val map = HashMap<String, String>()
map["asd"] = "s"
map.put("34", "354")
However when I create a map with the Map interface I can only read them, what I'm doing wrong ?
val map: Map<String, String> = HashMap<String, String>();
map.put("24", "34") //error
map["23"] = "23" //error
Or maybe I'm confusing something about interfaces in Kotlin ?
In the first example map gets the type of HashMap,
in the second example you cast it to the Interface Map.
Map is a readonly map, there is no put/set, see here
In order to be able to edit the map, you should use MutableMap
When working with kotlin collections, one important consideration is that, kotlin categorizes its collections as mutable and immutable. this is in contrast to java, where no such categorization exists.
In kotlin for most collections you have a base interface which only supports read-only methods. In your case Map<K,V is an example of that, from the docs
Methods in this interface support only read-only access to the map;
read-write access is supported through the MutableMap interface.
this is the reason for error when you try to modify the map after val map: Map<String, String> = HashMap<String, String>();, even though the actual object is of type HashMap<String,String>, but the map reference is of type Map<String,String>, which will only provide read only operation.
Now if you use a class which implements MutableMap<K,V> then you can put values in map as well. this is the case with val map = HashMap<String, String>(), since here type of map is HashMap<K,V>, which extends MutableMap<K,V> and hence is mutable.
I use this common initialization format when I anticipate changing the implementation of the List interface at a later time:
List<Foo> foos = new ArrayList<Foos>();
In an effort to gain the same utility for the values within a Map, I attempted the following but my compiler whines about List<> and ArrayList<> being incompatible types.
Map<String, List<Foo>> fooMap = new HashMap<String, ArrayList<Foo>>;
I've been unable to find an explanation for why I cannot initialize the map in this manner and I'd like to understand the reasoning.
And, sure, this works...
Map<String, List<Foo>> foosMap = new HashMap<String, List<Foo>>;
// ... populate map
ArrayList<Foo> foosAryLst = (ArrayList)foosMap.get("key1");
... but I'm a curious castaphobe. I'd rather fix compile-time errors than runtime errors, things like this aggravate my OCD and the smell of casting conjures an odor similar to the urinal trough after free deep-fried asparagus night at the stadium.
My questions come down to:
Why can I not code my map values to an interface.
Is there a workaround that doesn't require casting?
Any input will be appreciated, thanks!
Sure, there's a workaround that doesn't require casting: don't cast; write
List<Foo> foosLst = foosMap.get("key1");
...and code to the interface with the List as well as the Map.
The root issue, though, is that a Map<String, ArrayList<Foo>> isn't substitutable wherever you'd use Map<String, List<Foo>>. In particular,
Map<String, List<Foo>> map = new HashMap<>();
map.put("foo", new LinkedList<Foo>());
works, but not if map is a Map<String, ArrayList<Foo>>. So one isn't a drop-in substitute for the other.
The declaration that you proposed
Map<String, List<Foos>> fooMap = new HashMap<String, ArrayList<Foos>>();
simply does not make sense: The variable fooMap has the type Map<String, List<Foos>>. This means:
every value that you obtain from this map is a List<Foos>
you may put every value into this list that is (of a subtype of) List<Foos>
If you wanted a map that has ArrayLists as its values, then you would declare it as
Map<String, ArrayList<Foos>> fooMap = new HashMap<String, ArrayList<Foos>>();
If you don't care about the list type, then you can say
Map<String, List<Foos>> fooMap = new HashMap<String, List<Foos>>();
But there's no sensible meaning of mixing the two. Even if you could write what you proposed, then you could still not obtain an ArrayList from this map, because this is simply not the type that fooMap was declared with.
In most cases,
Map<String, List<Foos>> fooMap = new HashMap<String, List<Foos>>();
should be appropriate. Depending on the use case, one could possibly go further by saying
Map<String, List<? extends Foos>> fooMap = new HashMap<String, List<? extends Foos>>();
This way, you can also put lists into the map that contain sublcasses of Foos, like
List<SpecialFoos> specialFoos = ...
fooMap.put("special", specialFoos);
But of course, it's up to you to decide whether this is necessary or not.
The core of the problem is that the compiler cannot keep track of what fooMap may have been assigned to at any particular point in the execution of your code, so there is no way for the compiler to know that
fooMap.put("abc", new ArrayList<Foo>())
should be legal, but that
fooMap.put("abc", new LinkedList<Foo>())
should not be.
All that the compiler knows about the typing of fooMap is its declared type Map<String, List<Foo>>. So, it enforces that whatever object to which you assign fooMap must be able to support all of the operations which a generic Map<String, List<Foo>> is capable of executing. The second line of code above is clearly legal for a Map<String, List<Foo>>, but not legal for a Map<String, ArrayList<Foo>>, so the compiler forbids you from assigning fooMap to a Map<String, ArrayList<Foo>>.
I see many examples about multimap but did not understand why Google Gauva is different?
Multimap<Integer, Set<String>> option4 = HashMultimap.create(); // Gauva
Map<Integer, Set<String>> opt = new HashMap<Integer, Set<String>>(); //Core Java
Is both above are behave same for holding data or different?
A MultiMap<A, B> associates a key of type A with a value of type Collection<B> (hence the name MultiMap)
A Map<A, B> associates a key of type A with a value of type B.
So, a MultiMap<Integer, Set<String>> can be viewed as a Map<Integer, Collection<Set<String>>. This should be obvious by reading the api documentation.
The difference is that with the second, Core Java implementation, you need to check whether the Set is there before you insert. Guava's Multimap takes care of that for you.
With Core Java:
Set<String> innerSet = opt.get(key);
if (innerSet == null) {
innerSet = new HashSet<String>();
opt.put(key, innerSet);
}
innerSet.add(value);
With Guava:
opt.put(key, value);
Guava takes care of initialising an otherwise absent Set to store the values, takes care of any threading issues (eg stops two threads from creating a new Set for the same key in parallel) and also provides a few useful methods that you'd otherwise need to implement by hand, such as getting all the values across all the Sets.
You misunderstood something. These are not even roughly equivalent:
Multimap<Integer, Set<String>> option4 = HashMultimap.create(); // Guava
Map<Integer, Set<String>> opt = new HashMap<Integer, Set<String>>(); //Core Java
In your example, opt4 would map a single Integer to a Collection of Sets of Strings.
That's exactly the point of using a Multimap, you don't have to explicitly deal with the second dimension. So in fact, the correct (equivalent) declaration would be:
SetMultimap<Integer, String> multimap = HashMultimap.create(); // Guava
and you can get a map view like this:
Map<Integer, Set<String>> mapView = multimap.asMap();
Nope, MultiMap means that there would be a collection of objects attached to each key.
Documentation: Multimap_Is_Not_A_Map
First of all com.google.common.collect.Multimap is not java.util.Map, it is in a separate hierarchy.
Secondly, you can all the operations with Map<Integer, Set<String>> that Multimap interface requires but you will have to implement them yourself while HashMultimap offers ready implementation.
I know it's a noob question but i cant find anything online.I have this HashMap :
HashMap<String, String> map = new HashMap<String, String>();
Element e = (Element) children.item(i);
map.put("title", ParseXMLmethods.getValue(e, "title"));
map.put("pubDate", ParseXMLmethods.getValue(e, "pubDate"));
map.put("link", ParseXMLmethods.getValue(e, "link"));
map.put("description",ParseXMLmethods.getValue(e, "description"));
localist.add(map);
I am getting an error on localist saying:"localist cannot be resolved". i know i have to declare localist but i don't know which variable type to use . Any help would be really appreciated.
First of all, declare your Map variables as the interface Map and initialize them as the implementation, e.g.
Map<String, String> map = new HashMap<String, String>();
you can also use the diamond operator <> to infer the template types, e.g.
HashMap<String, String> map = new HashMap<>();
While the above are not necessary, they are good practices.
Now, to declare your localist, you can do something like:
List<Map<String, String>> localist = new ArrayList<>();
which is a list of maps that map a string to a string.
If you're trying to add the map to a list, then you would use a List<Map> implementation, via ArrayList or LinkedList primarily. However why you would be keeping a list of Maps would be beyond me, I would recommend a class for this if you're storing multiple maps.
depending on how specific you want to be with your type, you could use ArrayList<HashMap<String, String>> localist = new ArrayList<HashMap<String, String>>();
As stated by the other answer, I would take some time to plan your Classes in your system first. Often if you can't find an answer online, it could suggest that your approach is not best practice or design when it comes to writing extensible and modular code.
You should always consider using abstract or interface types instead of concrete implementations for a start:
AbstractList<Map<String,String>>
As I understand it, there are a couple of ways (maybe others as well) to create a shallow copy of a Map in Java:
Map<String, Object> data = new HashMap<String, Object>();
Map<String, Object> shallowCopy;
// first way
shallowCopy = new HashMap<String, Object>(data);
// second way
shallowCopy = (Map<String, Object>) ((HashMap<String, Object>) data).clone();
Is one way preferred over the other, and if so, why?
One thing worth mentioning is that the second way gives an "Unchecked Cast" warning. So you have to add #SuppressWarnings("unchecked") to get around it, which is a little irritating (see below).
#SuppressWarnings("unchecked")
public Map<String, Object> getDataAsMap() {
// return a shallow copy of the data map
return (Map<String, Object>) ((HashMap<String, Object>) data).clone();
}
It's always better to copy using a copy constructor. clone() in Java is broken (see SO: How to properly override clone method?).
Josh Bloch on Design - Copy Constructor versus Cloning
If you've read the item about cloning in my book, especially if you read between the lines, you will know that I think clone is deeply broken. [...] It's a shame that Cloneable is broken, but it happens.
Bloch (who by the way, designed and implemented the Collection framework) even went further in saying that he only provides the clone() method just "because people expect it". He does NOT actually recommend using it at all.
I think the more interesting debate is whether a copy constructor is better than a copy factory, but that's a different discussion altogether.
Neither of the two: the constructor that you are referring to is defined for the HashMap implementation of a Map, (as well as for others) but not for the Map interface itself (for example, consider the Provider implementation of the Map interface: you will not find that constructor).
On the other hand it is not advisable to use the clone() method, as explained by Josh Bloch.
In respect of the Map interface (and of your question, in which you ask how to copy a Map, not a HashMap), you should use Map#putAll():
Copies all of the mappings from the specified map to this map
(optional operation). The effect of this call is equivalent to that of
calling put(k, v) on this map once for each mapping from key k to
value v in the specified map.
Example:
// HashMap here, but it works for every implementation of the Map interface
Map<String, Object> data = new HashMap<String, Object>();
Map<String, Object> shallowCopy = new HashMap<String, Object>();
shallowCopy.putAll(data);
Copy a map without knowing its implementation:
static final Map shallowCopy(final Map source) throws Exception {
final Map newMap = source.getClass().newInstance();
newMap.putAll(source);
return newMap;
}