Are there any differences between Map.of("key", "value") and Collections.singletonMap("key", "value")?
Are there any practices on which one is to be preferred over another if I just need to store one mapping for Java 9 and above?
Map.of
Map.of can only be used in Java 9 and above. It can be used to store 0 to 10 key-value pairs. See https://docs.oracle.com/javase/9/docs/api/java/util/Map.html#of-- and following. See also https://docs.oracle.com/javase/9/docs/api/java/util/Map.html#immutable:
The Map.of() and Map.ofEntries() static factory methods provide a
convenient way to create immutable maps. The Map instances created by
these methods have the following characteristics:
They are structurally immutable. Keys and values cannot be added, removed, or updated. Calling any mutator method will always cause
UnsupportedOperationException to be thrown. However, if the contained
keys or values are themselves mutable, this may cause the Map to
behave inconsistently or its contents to appear to change.
They disallow null keys and values. Attempts to create them with null keys or values result in NullPointerException.
They are serializable if all keys and values are serializable.
They reject duplicate keys at creation time. Duplicate keys passed to a static factory method result in IllegalArgumentException.
The iteration order of mappings is unspecified and is subject to change.
They are value-based. Callers should make no assumptions about the identity of the returned instances. Factories are free to create new
instances or reuse existing ones. Therefore, identity-sensitive
operations on these instances (reference equality (==), identity hash
code, and synchronization) are unreliable and should be avoided.
They are serialized as specified on the Serialized Form page.
Similarily, there is List.of and Set.of.
Collections.singletonMap
Collections.singletonMap is available since Java 1.3. It can only be used to store one key-value pair. See https://docs.oracle.com/javase/9/docs/api/java/util/Collections.html#singletonMap-K-V-.
In general, singletons always contain exactly one value. A singleton class is one that has exactly one instance. A singleton map has exactly one mapping, a singleton list has exactly one element and so on.
Related
I google out the usage of identity hash map but doesn't found a good answer. I also doesn't got the java doc explaination below :
A typical use of this class is topology-preserving object graph transformations, such as serialization or deep-copying. To perform such a transformation, a program must maintain a "node table" that keeps track of all the object references that have already been processed. The node table must not equate distinct objects even if they happen to be equal. Another typical use of this class is to maintain proxy objects. For example, a debugging facility might wish to maintain a proxy object for each object in the program being debugged.
Can some one please provide a good use case of identity hash map ?
I guess the important point here is
The node table must not equate distinct objects even if they happen to be equal
If you add a key value pair to a map the e.g. hashmap will check if the key already exists using the equal method. But there are cases where you want to compare the key on its real identify which in Java is the object reference (address). As stated in the Java doc one use case could be a map that manages proxy objects. If you have two objects which are "equal" you still want to create a separate proxy object for both of them. And as for caching you want to store those proxy objects in a map. Then you use the identity map with the source object as key and the proxy object as value.
Hope this makes it a bit clearer.
I read it here:
Immutable objects are good Map keys and Set elements, since these
typically do not change once created.
Because these collections rely on hashing, fields that contribute to their hashCode should be immutable.
When a HashMap wants to store a key-value, it uses hashCode of its key and works out a place for the pair,
The same technique will be used for elements retrieval ( ex: contains,get, etc..). Now imagine hashCode upon element retrieval produces a value different than the one produced at the time the elements were added ? Would we be able to locate the element correctly? No.
HashSet is no different from a HashMap.
It's all about having a hashCode and equals methods that are able to compare objects correctly, immutability makes it easier to reason about the correctness of these methods.
I made a post a few days ago about using a HashMap in a simple banking program, but I'm having issues with using Objects as keys.
HashMap <Account,Client> HM = new HashMap<Account, Client>();
HM.put(new Account(2193,"Uri"), new Client(2193,0,"Uri"));
HM.get(2193,"Uri");
Account and Client are classes in other parts of the source. My issue is that the HM.get isn't working as intended, and is giving me an error. Is there another way I'm to 'get' the value? Not sure how to use the key. Do note, the setup of the HashMap is without error.
Furthermore, is there a better way to go about this?
This will give you better idea. that why you need to override hashcode and equals method.
Why do I need to override the equals and hashCode methods in Java?
After overriding hashcode and equals method.
you need to use your object while getting data from hashMap.
HM.get(new Account(2193,"Uri"));
First of all this code does not compile as you are passing 2 arguments to get() which expects only 1 argument.
That argument is supposed to be the key you use in the map and has to be of the same type you declared while declaring your map, in your case HashMap <Account,Client> HM means that HM (which btw should be lowercase by convention) holds as keys objects of type Account and objects of type Client as values.
It would still compile if you did:
get(2193)
Since get() takes an Object but it would simply return a null.
You need to do get(new Account(2193,"Uri")).
Next you do not need to override equals and hashCode in those classes but it is highly recommended (others already pointed to links saying why). Also as per the doc you should make the keys immutable so they do not change, otherwise you might get strange behavior.
Note: great care must be exercised if mutable objects are used as map
keys. The behavior of a map is not specified if the value of an object
is changed in a manner that affects equals comparisons while the
object is a key in the map. A special case of this prohibition is that
it is not permissible for a map to contain itself as a key. While it
is permissible for a map to contain itself as a value, extreme caution
is advised: the equals and hashCode methods are no longer well defined
on such a map.
For more detailed description of the Map interface follow Oracle's tutorial
Are there any constraint on the key type in the hash map and hash table?----Interview Question.
I think yes we can customize it as needed.
Technically, no. Generally, you want to use an object that implements equals() and hashCode() although that is not strictly necessary. If you don't, then it will use the base implementations defined by Object which compare object identity. A lot of times, that is not appropriate but sometimes it's fine.
Technically the key doesn't need to be immutable as long as the values used in the equals() and hashCode() implementations are immutable. For example, if your class Foo uses a string "foo" as part of its has then that value "foo" must not change. That's because hash maps put the keys into buckets based on the hashCode() value for efficiency reasons. If the hashCode suddenly changes, the hash map is unaware and the key will now live in the wrong bucket and you'll run into nasty bugs because it's then possible to have "duplicate" objects in your map. Hope that makes sense.
Several things to consider:
Just about the "Type", you cannot use primitive type. This is language constraint of Java. e.g. HashMap<int, Foo> is not valid, you need to use HashMap<Integer, Foo>
Base on the way HashMap work, key should have a meaningful implementation of hashCode() and equals(). How it is "meaningful" depends on your need. It may be possible that the default implementation in Object already serve your need, but you need to aware of it.
Once an object instance is put into the Map as key, its hashCode() and equals() should stay consistent. You should never put to a map, and change the state of the object instance as Key and cause hashCode()/equals() returns different value. The easiest way to ensure it is of course use an immutable object as key. However it is still fine that you use mutable object, but in your code, you ensure changing state of keys are not happening.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Why does HashSet implementation in Sun Java use HashMap as its backing?
I know what a hashset and hashmap is - pretty well versed with them.
There is 1 thing which really puzzled me.
Example:
Set <String> testing= new HashSet <String>();
Now if you debug it using eclipse right after the above statements, under debugger variables tab, you will noticed that the set 'testing' internally is implemented as a hashmap.
Why does it need a hashmap since there is no key,value pair involved in sets collection
It's an implementation detail. The HashMap is actually used as the backing store for the HashSet. From the docs:
This class implements the Set interface, backed by a hash table (actually a HashMap instance). It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time. This class permits the null element.
(emphasis mine)
The answer is right in the API docs
"This class implements the Set interface, backed by a hash table (actually a HashMap instance). It makes no guarantees as to the iteration order of the set; in particular, it does not guarantee that the order will remain constant over time. This class permits the null element.
This class offers constant time performance for the basic operations (add, remove, contains and size), assuming the hash function disperses the elements properly among the buckets. Iterating over this set requires time proportional to the sum of the HashSet instance's size (the number of elements) plus the "capacity" of the backing HashMap instance (the number of buckets). Thus, it's very important not to set the initial capacity too high (or the load factor too low) if iteration performance is important."
So you don't even need the debugger to know this.
In answer to your question: it is an implementation detail. It doesn't need to use a HashMap, but it is probably just good code re-use. If you think about it, in this case the only difference is that a Set has different semantics from a Map. Namely, maps have a get(key) method, and Sets do not. Sets do not allow duplicates, Maps allow duplicate values, but they must be under different keys.
It is probably really easy to use a HashMap as the backing of a HashSet, because all you would have to do would be to use hashCode (defined on all objects) on the value you are putting in the Set to determine if a dupe, i.e., it is probably just doing something like
backingHashMap.put(toInsert.hashCode(), toInsert);
to insert items into the Set.
In most cases the Set is implemented as wrapper for the keySet() of a Map. This avoids duplicate implementations. If you look at the source you will see how it does this.
You might find the method Collections.newSetFromMap() which can be used to wrap ConcurrentHashMap for example.
The very first sentence of the class's Javadoc states that it is backed by a HashMap:
This class implements the Set interface, backed by a hash table (actually a HashMap instance).
If you'll look at the source code of HashSet you'll see that what it stores in the map is as the key is the entry you are using, and the value is a mere marker Object (named PRESENT).
Why is it backed by a HashMap? Because this is the simplest way to store a set of items in a (conceptual) hashtable and there is no need for HashSet to re-invent an implementation of a hashtable data structure.
It's just a matter of convenience that the standard Java class library implements HashSet using a HashMap -- they only need to implement one data structure and then HashSet stores its data in a HashMap with the actual set objects as the key and a dummy value (typically Boolean.TRUE) as the value.
HashMap has already all the functionality that HashSet requires. There would be no sense to duplicate the same algorithms.
it allows you to easily and quickly determine whether an object is already in the set or not.