ImmutableMap.of() workaround for HashMap in Maps? - java

There are utility methods to create ImmutableMap like Immutable.of(Key, value) and its overload.
But such methods don't exist for HashMap or LinkedHashMap in Maps class.
Is there any better way to do this or Guava assumes such a map is always a constant map and ImmutableMap is best option to go with and don't need to provide a utility for HashMap.

Why would you want those for a regular HashMap or LinkedHashMap? You can just do this:
Map<String, Object> map = Maps.newHashMap();
map.put(key, value);
The thing with ImmutableMap is that it is a little bit more cumbersome to create; you first need to make a Builder, then put the key-value pairs in the builder and then call build() on it to create your ImmutableMap. The ImmutableMap.of() method makes it shorter to write if you want to create an ImmutableMap with a single key-value pair.
Consider what you'd have to write if you wouldn't use the ImmutableMap.of() method:
ImmutableMap<String, Object> map = ImmutableMap.builder()
.put(key, value);
.build();

Try Maps.newHashMap(ImmutableMap.of(...))
Maps.newHashMap(Map map)

The difference is that for an immutable map, you have to provide everything up-front, because you can't change it after construction. For mutable maps, you can just create the map and then add the entries. Admittedly this makes it slightly harder to create a map in a single expression, but that doesn't tend to be a problem where you'd want a mutable map anyway, in my experience.

cannot you use the copyOf method of ImmutableMap described here?
it should be something like
Map newImmutableMap = ImmutableMap.copyOf(yourMap);

ImmutableMap.of() returns a hash based immutable map without order.
If you need ordered immutable map, ImmutableSortedMap.of() is a choice.
ImmutableSortedMap provides methods such as firstKey(), lastKey(), headMap(K) and tailMap(K);
Both classes provide copyOf(Map) method.

Related

Safely pass HashMap values, without value collection escaping

If I have a hashmap like this:
private final Map<String, Collection<String>> descriptions = new HashMap<>();
How do I pass the values safely to an alien method?
If I do this:
myOtherObject.outputDesc(descriptions.values());
then myOtherObject could change the values.
Would this be a safe way of doing this?
myOtherObject.outputDesc(new ArrayList<>(descriptions .values()));
Creating a copy of the collection as you suggested is a way you could go. But the extra effort for copying the list is not needed. Java provides a more convenient way for preventing value changes:
myOtherObject.outputDesc(Collections.unmodifiableCollection(descriptions.values()));

Compact way to create Guava Multimaps?

If I want to create a new Multimap with simple defaults, I curently need to do something like:
private final Multimap<Key, Value> providersToClasses = Multimaps
.newListMultimap(
new HashMap<Key, Collection<Value>>(),
new Supplier<List<Value>>() {
#Override
public List<Value> get() {
return Lists.newArrayList();
}
});
...because Java can't infer the correct types if Maps.newHashMap is used for the backing map. Of course, this can be refactored into a separate method, but is there already a way to write it more concisely?
Why aren't you using ArrayListMultimap.create() for such a simple case? It's the default way to create the simple HashMap/ArrayList that is probably the most common used multimap.
I run into this problem when writing clients and building up maps of query params. A nice succinct pattern I like for constructing multi-maps is to use ImmutableMultiMap#builder
Multimap<String, String> queryParams =
ImmutableMultimap.<String, String>builder()
.put("key-1", "value-1")
.put("key-1", "value-2")
.build();
The Guava documentation states that the create method advocated by some other answers "will soon be deprecated" in favour of the different forms presented below, and should therefore be avoided.
From Guava 21.0 onwards, the recommended way of creating a Multimap object where values are stored in ArrayList collections is the following:
MultimapBuilder.hashKeys().arrayListValues().build();
You can also use parameters if you want to specify the expected number of keys in your map and the expected number of values per key:
MultimapBuilder.hashKeys(expectedKeys).arrayListValues(expectedValuesPerKey).build();
Finally, you can create a new Multimap from an existing one using this construct:
MultimapBuilder.hashKeys().arrayListValues().build(multimap);
If you want to use data structures other than ArrayLists in your Multimap, you can replace the call to arrayListValues() by a number of other ones, listed here.
Here is compact solution:
Multimap<Integer, String> multi = HashMultimap.create();
In Java 8 this is much nicer, for all kinds of multimaps. This is for two reasons:
Because the compiler uses target types for type inference, you don't have to provide explicit type arguments for the HashMap contructor.
Constructor method references can be used to create the ArrayList factory.
It looks like this:
Multimap<Key, Value> providersToClasses =
Multimaps.newListMultimap(new HashMap<>(), ArrayList::new);
To answer the original type inference problem, though, you can also specify the generic types on a static method using Maps.<Key, Collection<Value>>newHashMap(), but it's certainly not more concise than new HashMap<Key, Collection<Value>>() (it may be more consistent).

Can I have a key-key map (as opposed to key-value) in Java?

What if I need to quickly search not only by the key but also by value. In other words, is there a construction like key-key as opposed to key-value?
Sounds like you want a bimap - I'd use the implementations in Guava if I were you; there's a BiMap interface, and various implementations such as HashBiMap and ImmutableBiMap.
Note that you generally view a BiMap from one "side" (K1 to K2), and just call inverse() to get the opposite view of things (K2 to K1).
Several libraries have something like that. For example, Google Guava has a BiMap (bidirectional map). Unfortunately there's no bidirectional map in the standard Java library.
To clarify, you would have some sort of map with the following key:value pairs:
Map<String, String> map = new HashMap<String, String>();
map.put("foo", "Freddy");
map.put("bar", "Bobby");
Then, you would want to do map.get("foo") and get Freddy, or do map.get("Freddy") and get foo?
If so, check this post out.

What is the difference between the HashMap and Map objects in Java?

What is the difference between the following maps I create (in another question, people answered using them seemingly interchangeably and I'm wondering if/how they are different):
HashMap<String, Object> map = new HashMap<String, Object>();
Map<String, Object> map = new HashMap<String, Object>();
There is no difference between the objects; you have a HashMap<String, Object> in both cases. There is a difference in the interface you have to the object. In the first case, the interface is HashMap<String, Object>, whereas in the second it's Map<String, Object>. But the underlying object is the same.
The advantage to using Map<String, Object> is that you can change the underlying object to be a different kind of map without breaking your contract with any code that's using it. If you declare it as HashMap<String, Object>, you have to change your contract if you want to change the underlying implementation.
Example: Let's say I write this class:
class Foo {
private HashMap<String, Object> things;
private HashMap<String, Object> moreThings;
protected HashMap<String, Object> getThings() {
return this.things;
}
protected HashMap<String, Object> getMoreThings() {
return this.moreThings;
}
public Foo() {
this.things = new HashMap<String, Object>();
this.moreThings = new HashMap<String, Object>();
}
// ...more...
}
The class has a couple of internal maps of string->object which it shares (via accessor methods) with subclasses. Let's say I write it with HashMaps to start with because I think that's the appropriate structure to use when writing the class.
Later, Mary writes code subclassing it. She has something she needs to do with both things and moreThings, so naturally she puts that in a common method, and she uses the same type I used on getThings/getMoreThings when defining her method:
class SpecialFoo extends Foo {
private void doSomething(HashMap<String, Object> t) {
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
// ...more...
}
Later, I decide that actually, it's better if I use TreeMap instead of HashMap in Foo. I update Foo, changing HashMap to TreeMap. Now, SpecialFoo doesn't compile anymore, because I've broken the contract: Foo used to say it provided HashMaps, but now it's providing TreeMaps instead. So we have to fix SpecialFoo now (and this kind of thing can ripple through a codebase).
Unless I had a really good reason for sharing that my implementation was using a HashMap (and that does happen), what I should have done was declare getThings and getMoreThings as just returning Map<String, Object> without being any more specific than that. In fact, barring a good reason to do something else, even within Foo I should probably declare things and moreThings as Map, not HashMap/TreeMap:
class Foo {
private Map<String, Object> things; // <== Changed
private Map<String, Object> moreThings; // <== Changed
protected Map<String, Object> getThings() { // <== Changed
return this.things;
}
protected Map<String, Object> getMoreThings() { // <== Changed
return this.moreThings;
}
public Foo() {
this.things = new HashMap<String, Object>();
this.moreThings = new HashMap<String, Object>();
}
// ...more...
}
Note how I'm now using Map<String, Object> everywhere I can, only being specific when I create the actual objects.
If I had done that, then Mary would have done this:
class SpecialFoo extends Foo {
private void doSomething(Map<String, Object> t) { // <== Changed
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
}
...and changing Foo wouldn't have made SpecialFoo stop compiling.
Interfaces (and base classes) let us reveal only as much as is necessary, keeping our flexibility under the covers to make changes as appropriate. In general, we want to have our references be as basic as possible. If we don't need to know it's a HashMap, just call it a Map.
This isn't a blind rule, but in general, coding to the most general interface is going to be less brittle than coding to something more specific. If I'd remembered that, I wouldn't have created a Foo that set Mary up for failure with SpecialFoo. If Mary had remembered that, then even though I messed up Foo, she would have declared her private method with Map instead of HashMap and my changing Foo's contract wouldn't have impacted her code.
Sometimes you can't do that, sometimes you have to be specific. But unless you have a reason to be, err toward the least-specific interface.
Map is an interface that HashMap implements. The difference is that in the second implementation your reference to the HashMap will only allow the use of functions defined in the Map interface, while the first will allow the use of any public functions in HashMap (which includes the Map interface).
It will probably make more sense if you read Sun's interface tutorial
Map has the following implementations:
HashMap Map m = new HashMap();
LinkedHashMap Map m = new LinkedHashMap();
Tree Map Map m = new TreeMap();
WeakHashMap Map m = new WeakHashMap();
Suppose you have created one method (this is just pseudocode).
public void HashMap getMap(){
return map;
}
Suppose your project requirements change:
The method should return map contents - Need to return HashMap.
The method should return map key's in insertion order - Need to change return type HashMap to LinkedHashMap.
The method should return map key's in sorted order - Need to change return type LinkedHashMap to TreeMap.
If your method returns specific classes instead of something that implements the Map interface, you have to change the return type of getMap() method each time.
But if you use the polymorphism feature of Java, and instead of returning specific classes, use the interface Map, it improves code reusability and reduces the impact of requirement changes.
I was just going to do this as a comment on the accepted answer but it got too funky (I hate not having line breaks)
ah, so the difference is that in
general, Map has certain methods
associated with it. but there are
different ways or creating a map, such
as a HashMap, and these different ways
provide unique methods that not all
maps have.
Exactly--and you always want to use the most general interface you possibly can. Consider ArrayList vs LinkedList. Huge difference in how you use them, but if you use "List" you can switch between them readily.
In fact, you can replace the right-hand side of the initializer with a more dynamic statement. how about something like this:
List collection;
if(keepSorted)
collection=new LinkedList();
else
collection=new ArrayList();
This way if you are going to fill in the collection with an insertion sort, you would use a linked list (an insertion sort into an array list is criminal.) But if you don't need to keep it sorted and are just appending, you use an ArrayList (More efficient for other operations).
This is a pretty big stretch here because collections aren't the best example, but in OO design one of the most important concepts is using the interface facade to access different objects with the exact same code.
Edit responding to comment:
As for your map comment below, Yes using the "Map" interface restricts you to only those methods unless you cast the collection back from Map to HashMap (which COMPLETELY defeats the purpose).
Often what you will do is create an object and fill it in using it's specific type (HashMap), in some kind of "create" or "initialize" method, but that method will return a "Map" that doesn't need to be manipulated as a HashMap any more.
If you ever have to cast by the way, you are probably using the wrong interface or your code isn't structured well enough. Note that it is acceptable to have one section of your code treat it as a "HashMap" while the other treats it as a "Map", but this should flow "down". so that you are never casting.
Also notice the semi-neat aspect of roles indicated by interfaces. A LinkedList makes a good stack or queue, an ArrayList makes a good stack but a horrific queue (again, a remove would cause a shift of the entire list) so LinkedList implements the Queue interface, ArrayList does not.
As noted by TJ Crowder and Adamski, one reference is to an interface, the other to a specific implementation of the interface. According to Joshua Block, you should always attempt to code to interfaces, to allow you to better handle changes to underlying implementation - i.e. if HashMap suddenly was not ideal for your solution and you needed to change the map implementation, you could still use the Map interface, and change the instantiation type.
Map is the static type of map, while HashMap is the dynamic type of map. This means that the compiler will treat your map object as being one of type Map, even though at runtime, it may point to any subtype of it.
This practice of programming against interfaces instead of implementations has the added benefit of remaining flexible: You can for instance replace the dynamic type of map at runtime, as long as it is a subtype of Map (e.g. LinkedHashMap), and change the map's behavior on the fly.
A good rule of thumb is to remain as abstract as possible on the API level: If for instance a method you are programming must work on maps, then it's sufficient to declare a parameter as Map instead of the stricter (because less abstract) HashMap type. That way, the consumer of your API can be flexible about what kind of Map implementation they want to pass to your method.
In your second example the "map" reference is of type Map, which is an interface implemented by HashMap (and other types of Map). This interface is a contract saying that the object maps keys to values and supports various operations (e.g. put, get). It says nothing about the implementation of the Map (in this case a HashMap).
The second approach is generally preferred as you typically wouldn't want to expose the specific map implementation to methods using the Map or via an API definition.
Adding to the top voted answer and many ones above stressing the "more generic, better", I would like to dig a little bit more.
Map is the structure contract while HashMap is an implementation providing its own methods to deal with different real problems: how to calculate index, what is the capacity and how to increment it, how to insert, how to keep the index unique, etc.
Let's look into the source code:
In Map we have the method of containsKey(Object key):
boolean containsKey(Object key);
JavaDoc:
boolean java.util.Map.containsValue(Object value)
Returns true if this map maps one or more keys to the specified value. More formally, returns true if and only if this map contains at least one mapping to a value v such that (value==null ? v==null : value.equals(v)). This operation will probably require time linear in the map size for most implementations of the Map interface.
Parameters:value
value whose presence in this map is to betested
Returns:true
if this map maps one or more keys to the specified
valueThrows:
ClassCastException - if the value is of an inappropriate type for this map (optional)
NullPointerException - if the specified value is null and this map does not permit null values (optional)
It requires its implementations to implement it, but the "how to" is at its freedom, only to ensure it returns correct.
In HashMap:
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}
It turns out that HashMap uses hashcode to test if this map contains the key. So it has the benefit of hash algorithm.
You create the same maps.
But you can fill the difference when you will use it. With first case you'll be able to use special HashMap methods (but I don't remember anyone realy useful), and you'll be able to pass it as a HashMap parameter:
public void foo (HashMap<String, Object) { ... }
...
HashMap<String, Object> m1 = ...;
Map<String, Object> m2 = ...;
foo (m1);
foo ((HashMap<String, Object>)m2);
Map is interface and Hashmap is a class that implements Map Interface
Map is the Interface and Hashmap is the class that implements that.
So in this implementation you create the same objects
HashMap is an implementation of Map so it's quite the same but has "clone()" method as i see in reference guide))
HashMap<String, Object> map1 = new HashMap<String, Object>();
Map<String, Object> map2 = new HashMap<String, Object>();
First of all Map is an interface it has different implementation like - HashMap, TreeHashMap, LinkedHashMap etc. Interface works like a super class for the implementing class. So according to OOP's rule any concrete class that implements Map is a Map also. That means we can assign/put any HashMap type variable to a Map type variable without any type of casting.
In this case we can assign map1 to map2 without any casting or any losing of data -
map2 = map1

Multi-valued hashtable in Java

Is it possible to have multiple values for the same key in a hash table? If not, can you suggest any such class or interface which could be used?
No. That's kind of the idea of hash tables.
However, you could either roll your own with a Map<YourKeyObject, List<YourValueObject>> and some utility methods for creating the list if it's not present, or use something like the Multimap from Google Collections.
Example:
String key = "hello";
Multimap<String, Integer> myMap = HashMultimap.create();
myMap.put(key, 1);
myMap.put(key, 5000);
System.out.println(myMap.get(key)); // prints either "[1, 5000]" or "[5000, 1]"
myMap = ArrayListMultimap.create();
myMap.put(key, 1);
myMap.put(key, 5000);
System.out.println(myMap.get(key)); // always prints "[1, 5000]"
Note that Multimap is not an exact equivalent of the home-baked solution; Hashtable synchronizes all its methods, while Multimap makes no such guarantee. This means that using a Multimap may cause you problems if you are using it on multiple threads. If your map is used only on one thread, it will make no difference (and you should have been using HashMap instead of Hashtable anyway).
Values of a hash table is Object so you can store a List
In a hashtable, one would use a key/value pair to store information.
In Java, the Hashtable class accepts a single value for a single key. The following is an example of an attempt to associate multiple values to a single key:
Hashtable<String, String> ht = new Hashtable<String, String>();
ht.put("Answer", "42");
ht.put("Hello", "World"); // First value association for "Hello" key.
ht.put("Hello", "Mom"); // Second value association for "Hello" key.
for (Map.Entry<String, String> e : ht.entrySet()) {
System.out.println(e);
}
In an attempt to include multiple values ("World", "Mom") to a single key ("Hello"), we end up with the following result for printing the entries in the Hashtable:
Answer=42
Hello=Mom
The key/value pair of "Hello" and "World" is not in the Hashtable -- only the second "Hello" and "Mom" entry is in the Hashtable. This shows that one cannot have multiple values associate with a single key in a Hashtable.
What is really needed here is a multimap, which allows an association of multiple values to a single key.
One implementation of the multimap is Multimap from Google Collections:
Multimap<String, String> mm = HashMultimap.create();
mm.put("Answer", "42");
mm.put("Hello", "World");
mm.put("Hello", "Mom");
for (Map.Entry<String, String> e : mm.entries()) {
System.out.println(e);
}
This is similar to the example above which used Hashtable, but the behavior is quite different -- a Multimap allows the association of multiple values to a single key. The result of executing the above code is as follows:
Answer=42
Hello=Mom
Hello=World
As can be seen, for the "Hello" key, the values of "Mom" and "World" associated with it. Unlike Hashtable, it does not discard one of the values and replace it with another. The Multimap is able to hold on to multiple values for each key.
Rather than give yet another multipmap answer, I'll ask why you want to do this?
Are the multiple values related? If yes, then it's probably better that you create a data structure to hold them. If no, then perhaps it's more appropriate to use separate maps.
Are you keeping them together so that you can iterate them based on the key? You might want to look for an alternative indexing data structure, like a SkipList.
Just make your own:
Map<Object, List<Object>> multiMap = new HashMap<Object, List<Object>>();
To add:
public void add(String key, Object o) {
List<Object> list;
if (multiMap.containsKey(key)) {
list = multiMap.get(key);
list.add(o);
} else {
list = new ArrayList<Object>();
list.add(o);
multiMap.put(key, list);
}
}
As others pointed out, no. Instead, consider using a Multimap which can map many values for the same key.
The Google Collections (update: Guava) library contains one implementation, and is probably your best bet.
Edit: of course you can do as Eric suggests, and store a Collection as a value in your Hashtable (or Map, more generally), but that means writing unnecessary boilerplate code yourself. When using a library like Google Collections, it would take care of the low-level "plumbing" for you. Check out this nice example of how your code would be simplified by using Multimap instead of vanilla Java Collections classes.
None of the answers indicated what I would do first off.
The biggest jump I ever made in my OO abilities was when I decided to ALWAYS make another class when it seemed like it might be even slightly useful--and this is one of the things I've learned from following that pattern.
Nearly all the time, I find there is a relationship between the objects I'm trying to place into a hash table. More often than not, there is room for a class--even a method or two.
In fact, I often find that I don't even want a HashMap type structure--a simple HashSet does fine.
The item you are storing as the primary key can become the identity of a new object--so you might create equals and hash methods that reference only that one object (eclipse can make your equals and hash methods for you easily). that way the new object will save, sort & retrieve exactly as your original one did, then use properties to store the rest of the items.
Most of the time when I do that, I find there are a few methods that go there as well and before I know it I have a full-fledged object that should have been there all along but I never recognized, and a bunch of garbage factors out of my code.
In order to make it more of a "Baby step", I often create the new class contained in my original class--sometimes I even contain the class within a method if it makes sense to scope it that way--then I move it around as it becomes more clear that it should be a first-class class.
See the Google Collections Library for multimaps and similar such collections. The built-in collections don't have direct support for this.
What you're looking for is a Multimap. The google collections api provides a nice implementation of this and much else that's worth learning to use. Highly recommended!
Simple. Instead of
Hashtable<Key, Value>, use Hashtable<Key, Vector<Value>>.
You need to use something called a MultiMap. This is not strictly a Map however, it's a different API. It's roughly the same as a Map<K, List<V>>, but you wont have methods like entrySet() or values().
Apart from the Google Collections there is a apache Commons Collection object
for MultiMap
Following code without Google's Guava library. It is used for double value as key and sorted order
Map<Double,List<Object>> multiMap = new TreeMap<Double,List<Object>>();
for( int i= 0;i<15;i++)
{
List<Object> myClassList = multiMap.get((double)i);
if(myClassList == null)
{
myClassList = new ArrayList<Object>();
multiMap.put((double) i,myClassList);
}
myClassList.add("Value "+ i);
}
List<Object> myClassList = multiMap.get((double)0);
if(myClassList == null)
{
myClassList = new ArrayList<Object>();
multiMap.put( (double) 0,myClassList);
}
myClassList.add("Value Duplicate");
for (Map.Entry entry : multiMap.entrySet())
{
System.out.println("Key = " + entry.getKey() + ", Value = " +entry.getValue());
}

Categories