Can I declare a HashMap<key> instead of a HashMap<key,value>? - java

I'm trying to insert keys into a hashmap but I don't really need values inserted. I could but they wouldn't be used. I know hashmaps can accept null keys and values but only one null key,value pair. I could map.put(key,null) with the values being null but that method seems inefficient. My intention is that I'm going to use the map.containsKey(key) method to determine if a key exists in a hashmap which is why I don't need a value.
With that being said, is there a way to declare HashMap<key> instead of HashMap<key,arbitraryValue> so I won't have to add unnecessary null values? Sorry if this may be a dumb question.

As Jacob G. said, you should use a Set<E>.
A set is just a collection that does not contain any duplicates. The implementing class HashSet<E> actually uses a HashMap<K,V> under the hood, as mentioned by Ole V.V., but using a Set<E> in your code is the better approach IMO, because your problem does not require the values.
Additionally, there is a problem with using a HashMap<K,V> where all your values are null is in the get(K key) method. This method will return null if the requested key does not have an associated value. So how do you know if your call to get returned a valid or invalid null? i.e.
Map<Integer, Object> map = new HashMap<>();
// add entry 0 ->
map.put(0, null);
Object get1 = map.get(0); // returns null, so 0 must be a key in our map!
Object get2 = map.get(1); // also returns null, so is 1 a key too? No!
So, for your specific problem, I would try something like this!
Set<MyKey> set = new HashSet<>(); // or any implementing class
...
MyKey someKey = ...
// Check if your key set doesn't have some key, if so add it to the key set
if (!set.contains(someKey)) {
set.add(someKey);
}

Related

Is it possible to add a key without a value in hashtable Java?

I'm trying to work with Java's Junit Test. My goal is to create a hashtable as
Hashtable< String , Hashtable<String,String> > student =
new Hashtable<String, Hashtable<String, String>>();
Next, I want to add at first only the key. After that, when I have the value then add it to the key in hashtable.
Example
student.put("student1",null) ;
I tried to work with null, but during test process I get a
java.lang.NullPointerException
Is it not possible? Any ideas to how adding only the key without value?
Is it possible to add a key without a value in hashtable Java?
Short answer: No
Why?
Because it will throw and Exception if
* #exception NullPointerException if the key or value is
* <code>null</code>
And in the same source code has a validation
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
}
...
You can use a Map Instead.
HashTable is an older implementation and HashMap came as an advanced version with more capabilities. You can't call .equals() or .hashCode() on it as null isn't an object.
HashMap is a better replacement for single threaded applications or any time synchronization is not a requirement, because of the performance impact synchronization introduces. If you need a Threadsafe option you can also use ConcurrentHashMap
The documentation says that you can't:
Maps the specified key to the specified value in this hashtable.
Neither the key nor the value can be null.
The best that you can do, if you need the key, is to use an empty HashTable as the value:
student.put("student1", new Hashtable<>());
In most use cases you would not care about putting null into a HashMap. You can check which keys have a value assigned via the keySet() and treat everything else as null (since it was never assigned).
However, your question to me indicates that you need to distinguish three states: Key-Value pair, key that were never assigned a value, and keys that were explicitly assigned a null value.
Since the default HashMap does not support this behavior, you could implement your own class that implements the Map interface. It basically only wraps a HashMap, with a few important exceptions:
When you assign a value of null to a key, you put the key into a Set of "NullKeys" instead of into the HashMap.
When you retrieve a key, check whether it is in the "NullKey" Set. If yes, return null, otherwise look into the HashMap.
There are some special cases (overwriting an existing value with null etc.) but this would be the basic strategy.
(I am not sure whether this is a useful class to have other than in very specialized scenarios but it would meet your requirements.)

Updating HashMap in java

Do I need to remove value and then add or can I directly add it in HashMap and it will efficiently updated ?
i.e.
HashMap<String, String> person = new HashMap<String, String>();
person.add("name", "John");
now which would be a better/efficient way to update above key value :
a)
person.remove("name");
person.add("name", "jamy");
b)
person.add("name", "jamy");
or are both just the same ?
This is a very small example. Considering a large HashMap containing other HashMaps, which would be better option and is there any even more efficient way to do so ?
You can put the new value. It will substitute the old one.
From javadoc:
If the map previously contained a mapping for the key, the old value is replaced.
Note that the method is put, not add. add is not a method of Hashmap
Edited: I added the reference link to the documentation as Naman Gala commented.
Use put method, as it will replace value for given key if key exist , otherwise it will create new entry
java.util.HashMap provides put method to add key and object pair in the map. You do not have to remove the object if you want to update the HashMap object. It will return the previous object if there is any object in the map with the same key. Otherwise, it will simply return null. You do not have to remove it every time. Just use
java.util.HashMap.put(key, object);

Does ConcurrentHashmap size() method count null keys?

Lets say I have a concurrenthashmap with some keys and values that are not null. Later these keys can become null, then what happens? Are they automatically removed from concurrenthashmap or do they stay there as null? Does the size() method count them?
Most Java Maps can contain null values.
The following code is perfectly valid and will return a size of 1.
Map m = new HashMap<String, String>();
m.put("foo", null);
System.out.println(m.size()); //will print "1"
This is because HashMap allows for null values.
Turns out, however, based on my testing, that the following code will NOT work.
Map m = new ConcurrentHashMap<String, String>();
m.put("foo", null); //Will throw a NullPointerException
This is because, apparently, ConcurrentHashMap does not allow for null values.
According to the Javadoc(http://docs.oracle.com/javase/7/docs/api/java/util/Map.html):
Some map implementations have restrictions on the keys and values they may contain. For example, some implementations prohibit null keys and values, and some have restrictions on the types of their keys.
So, there you have it. Hope this helps :)
From ConcurrentHashMap API:
Like Hashtable but unlike HashMap, this class does not allow null to be used as a key or value.

Understanding HashMap<K,V>

Ok, here is the bit I do not understand.
If you attempt to retrieve an object using the get() method and null is returned, it is still possible that null may be stored as the object associated with the key you supplied to the get() method. You can determine if this is the case by passing your key of the object to containsKey() method for map. This returns true if key is stored in the map
So, how is containsKey() supposed to tell me if the value associated with the key supplied is null?
This is the reference if you wanna check. Page 553
Map<String, Object> map = new HashMap<String, Object>();
map.put("Foo", null);
System.out.println(map.containsKey("Foo"));
System.out.println(map.containsKey("Boo"));
OUTPUT:
true
false
get() returns null in two cases:
The key does not exist in the map.
The key does exist but the associated value is null.
You can't tell from get() which is true. However, containsKey() will tell you if the key was present in the map, regardless of whether its associated value was null.
Consider this simple snippet of code:
Map<String, String> m = new HashMap<String, String>();
m.put("key1", "value1");
m.put("key2", null);
System.out.println("m.get(\"key1\")=" + m.get("key1"));
System.out.println("m.containsKey(\"key1\")=" + m.containsKey("key1"));
System.out.println("m.get(\"key2\")=" + m.get("key2"));
System.out.println("m.containsKey(\"key2\")=" + m.containsKey("key2"));
System.out.println("m.get(\"key3\")=" + m.get("key3"));
System.out.println("m.containsKey(\"key3\")=" + m.containsKey("key3"));
As you can see I put in the map two values, one of which is null. Thene i asked the map for three values: two of them are present (one is null), one is not. Look at the result:
m.get("key1")=value1
m.containsKey("key1")=true
m.get("key2")=null
m.containsKey("key2")=true
m.get("key3")=null
m.containsKey("key3")=false
The second and the third are the tricky part. key2 is present with null value so, using get() you cannot discriminate whether the element is not in the map or is in the map with a null value. But, using containsKey() you can, as it returns a boolean.
(get() == null && containsKey()) == value is null
containsKey would tell you if the key is in the hashmap at all. Consider the case where a key is present with null value and the other case in which the key which you are looking for is not at all in the hashmap.

Find a object key from a HashMap

I have a HashMap having key as my own object and key as ArrayList of String. Is there a way to get the key object from the map which is equal to another object without iterating the map. Please note that my object has implemented equals & hashcode. And it only uses 2 attribute of the class to compare. The another object which I am trying to find in the keys of the map has those 2 attribute equal but the other attributes may be different in the key of the map.
//The actual map
private HashMap<FileDetail, ArrayList<String>> map = new HashMap<FileDetail, ArrayList<String>>();
//object to search in above map without iteration.
FileDetail file = some object;
I want to get the reference of the "file" object in the keys of the map.
No you can't do that. HashMap are supposed to work the other way : you have the key, you're looking for the object.
If you have an object and you want to find the key, there's probably something wrong in your logic and your looking in a wrong direction to solve your problem.
If you don't want to iterate over the keySet, then you can use Guava's BiMap. A biMap has an inverse view which is another bimap containing reversed keys and values. This is how you would use it:
BiMap<FileDetail, ArrayList<String>> biMap = HashBiMap.create();
//object to search in above map without iteration.
FileDetail file = some object;
FileDetail key = biMap.inverse().get(biMap.get(file));
If you really need to do this without iteration over the keySet (e.g. because the map is very large), I suggest storing both the key and the list as values in the map. Either create some specific class encapsulating both, or use a simple pair class. The map would look like:
Map<FileDetail, Pair<FileDetail, List<String>>>
If you can't change the type of the map, you can use a second Map<FileDetail, FileDetail> where key and value are always the same objects.
This question is five years old, but I had the same question just today, and found this page. I thought I'd share the solution I decided upon using, which is not described in any of the existing answers and avoids iterating over all the keys in the map. (Please be gentle; this is my first posting on SO. It's tough finding questions I can answer that don't already have answers. Moreover, every question I've had to date has already been asked on SO. I've been using SO for years, with no ability to comment or vote on answers.)
As has been stated already, maps are designed so that when you have a key, you look up a value. That being the case, the answer is to use the key also as the value, so that when you perform a lookup using an arbitrary key, which equals your original key but is not necessarily == to it, you get back the original key. The issue then, is how to get what you originally intended to be the value.
My solution depends on having control of the class used for the key, and control of the map, with the ability to redefine them, which appears to be the case for the OP. In the OP's example, this would be control of the FileDetail class and of the private map variable. Assuming such control, the FileDetail class would be modified to contain a member variable of type ArrayList<String>, which for my sample code below I'll call list, with associated setter and getter methods. For the private map variable, it would be defined thusly:
private HashMap<FileDetail, FileDetail> map = new HashMap<>();
Now, when you want to put a new ArrayList<String> object in the map, assigned to a specific FileDetail key, you assign the ArrayList<String> object to the FileDetail's ArrayList<String> member variable instead, and then place the FileDetail object in the map.
public void putInMap(FileDetail fd, ArrayList<String> al) {
// Ignoring null conditions for simplicity...
fd.setList(al);
map.put(fd, fd);
}
Later, when you get some arbitrary FileDetail object (one that equals the key but isn't necessarily == to it), and you want the associated key, it's a matter of doing a normal lookup:
FileDetail otherFd = getArbitraryFileDetail();
FileDetail originalKeyFd = map.get(otherFd);
And to get the associated ArrayList<String> after having performed the above:
ArrayList<String> al = originalKeyFd.getList();
Certainly this all hinges on the implementations of the equals and hashCode methods of the FileDetail class, but the OP already had those methods defined as desired.
Hope this helps anyone who, like me, comes to this page with a similar situation.
You are likely looking for a Bidirectional Map, Apache Commons Collections includes this as part of the library (im sure there are other imeplementations as well.) A bidirectional map, just as the name implies, is a map but written so as to make looking up by key or by value efficient.
In Java, HashMap associates a key with a value, not the other way around.
You can retrieve a Set of all of the keys using HashMap.keySet(), or alternatively iterate over all of the entries using HashMap.entrySet():
for (Entry <FileDetail, ArrayList<String>> entry : map.entrySet()) {
FileDetail key = entry.getKey();
if (shouldProcess(key)) {
ArrayList<String> list = entry.getValue();
processList(list);
}
}
We get the key object from Hashmap without iterating the keyset of HashMap by converting keyset to ArrayList. This is a simple example:
//Creating hashmap
HashMap<String, String> map = new HashMap<String, String>();
//Adding elements into the map
map.put("1", "Amit");
map.put("2", "Ananth");
map.put("3", "Sunil");
//Get the list from keyset
ArrayList myKeyList = new ArrayList(map.keySet());
//object to search in above map without iteration.
String myobj = "3";
System.out.println(myKeyList.get(myKeyList.indexOf(myobj)));

Categories

Resources