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.
Related
There are a couple of ways in Guava to create a sorted immutable multiMap. One way is to first create a ListMultiMap with the keys as a tree and then turn it into an immutable multiMap.
Using a ListMultiMap we can have duplicate values for the same key:
ListMultimap<Integer, String> mutableMap = MultimapBuilder.treeKeys().arrayListValues().build();
return ImmutableListMultimap.copyOf(mutableMap);
Using a TreeMap we won't have duplicate values for the same key:
TreeMultimap<Integer, String> mutableMap = TreeMultimap.create(Ordering.natural(), Ordering.arbitrary());
return ImmutableListMultimap.copyOf(mutableMap);
The problem is that in both cases the immutable interface is generic and doesn't give a way to access the keys in a sorted manner so that we could have e.g. tailMap and headMap which are found in Java's NavigationalMap.
Is there a way to have an immutable sorted multi map in Guava that gives access to tailMap and headMap? Or do I need to just manually build an ImmutableSortedMap<Integer, ImmutableList<String>> to get this functionality?
You can use your custom ListMultimap with treeKeys() and cast the resulting map — it's safe as guaranteed by Guava's contract:
Uses a naturally-ordered TreeMap to map keys to value collections.
The collections returned by Multimap.keySet(), Multimap.keys(), and Multimap.asMap() will iterate through the keys in sorted order.
For all multimaps generated by the resulting builder, the Multimap.keySet() can be safely cast to a SortedSet, and the Multimap.asMap() can safely be cast to a SortedMap.
Example:
ListMultimap<Integer, String> multimap = MultimapBuilder.treeKeys().arrayListValues().build();
multimap.putAll(ImmutableMultimap.of(1, "one", 1, "uno", 2, "two", 42, "forty-two"));
// {1=[one, uno], 2=[two], 42=[forty-two]}
SortedMap<Integer, List<String>> sortedMap = (SortedMap<Integer, List<String>>) Multimaps.asMap(multimap); // safe, see javadoc
// `.asMap()` directly on `multimap` would give you SortedMap<Integer, Collection<String>>
// SortedMap<Integer, Collection<String>> sortedMap = (SortedMap<Integer, Collection<String>>) multimap.asMap();
SortedMap<Integer, List<String>> tailMap = sortedMap.tailMap(2);
// {2=[two], 42=[forty-two]}
Given a Map, how can I make an immutable map using Guava? I know one way through Collections.unmodifiableMap but is there any other way using Guava?
Map<String, String> realMap = Maps.newHashMap();
realMap.put("A", "B");
// any other alternative?
Map<String, String> unmodifiableMap = Collections.unmodifiableMap(realMap);
I am populating my realMap with some entries and then I need to make it Immutable so that no one can modify it. I am just trying to see if there is any alternative using Guava? I did some search but I cannot find it.
You're looking for ImmutableMap.copyOf():
ImmutableMap<String, String> immutableMap = ImmutableMap.copyOf(realMap);
Keep in mind that, as opposed to unmodifiableMap() which only creates a wrapper to its argument, this actually copies it to a new map. That can mean a slight performance hit, but it also means there's no possibility of the map being modified accidentally through realMap.
What is the difference between
Map map = new HashMap<Long, String>();
and
Map map = new HashMap<>();
Which is better for use and why?
The specification HashMap<Long, String>() is simply for the parameter types. But both the use cases you have shown are bad (I would just call it wrong) because the map object has no parameter types. What you should be doing is
Map<Long, String> map = new HashMap<Long, String>();
which is identical to
Map<Long, String> map = new HashMap<>();
The only difference between the two lines is whether you want to rely on automatic type inference of the JDK.
Addendum:
As Boris confirmed, in pre-JDK7, the automatic type inference was not possible, and the second way of initializing the map would not have compiled.
If you are using an IDE (really hope you are), please pay attention to warning about raw use of parametrized types.
Really it should be Map<Long, String> map = new HashMap<>(); The 2 fields in the <> represent the key and value type of the map. So in this example it's a map of Strings which a referenced by Long values. Including them in the declaration forces the Map to ensure that the map can only have specific Key/Value types. It used to be that the types had to be included in the <> of the assignment but it hasn't been needed since Java 7.
I have input data (Timestamp, Json string) which I store in a HashMap<Long, String>. To process the JSON string I use an iterator.
I use Iterator<Entry<Long, String>> it = data.entrySet().iterator(); to get the entrySet as iterator.
My problem is now that the HashMap is organized as follows:
123,{String1}
124,{String2}
125,{String3}
Better expressed: I add A to the HashMap, Z to the HashMap, E to the HashMap, I to the HashMap. I expect the order A, Z, E, I and I want the same order in the iterator.
If I put it in an iterator I get:
124, {String2}
123, {String1}
125, {String3}
The order of the itarator is different from the HashMap order. For me the order of the iterator has to be exactly the same as the order of the HashMap. What I'm doing wrong, that the iterator is changing the order of the data?
HashMap is not organised in any particular order, or more precisely, the order is not guaranteed. If you want an ordered map, use SortedMap with a TreeMap implementation providing a Comparator if you need to override the default ordering of keys.
Additional to the above findings,
Even you can use LinkedHashMap as given below,LinkedHashMap will make sure values stored in the order of insertion.
public static void main(String[] args) {
Map<Integer, String> map = new LinkedHashMap<Integer, String>();
Map<Integer, String> map2 = new HashMap<Integer, String>();
map.put(1, "oneone");
map.put(3, "twoone");
map.put(2, "threeone");
map2.put(1, "oneone");
map2.put(3, "twoone");
map2.put(2, "threeone");
for(Entry<Integer, String> entry:map.entrySet()){
System.out.println(entry.getKey());
}
for(Entry<Integer, String> entry:map2.entrySet()){
System.out.println(entry.getKey());
}
}
Here result will be,
1
3
2
1
2
3
HashMap documentation says that
This class makes no guarantees as to the order of the map; in
particular, it does not guarantee that the order will remain constant
over time.
So you should not rely on the order while you are iterating views entrySet or keySet or values.
Some implementations of Map such as TreeMap provide ordering guarantee as #Oleg S and #Smutje have already suggested.
Excerpt from the java.util.Map API doc: "The Map interface provides three collection views, which allow a map's contents to be viewed as a set of keys, collection of values, or set of key-value mappings. The order of a map is defined as the order in which the iterators on the map's collection views return their elements. Some map implementations, like the TreeMap class, make specific guarantees as to their order; others, like the HashMap class, do not."
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>>>();