I have a HashMap with String key and String value. I want to get an item from list, I tried to give key and wanted to get value but it gives an error.
The following example how can I get "both" value with give the key "blazer"?
HashMap<String,String> upper = new HashMap<>();
upper.put("shoulder","both");
upper.put("blazer","both");
if(upper.get(upper.get("blazer"))) {} //gives an "incompatible types" error.
//Error: Required: boolean Found: java.lang.String
Understand that upper.get(key) will not return a boolean value. You have defined your HashMap as follows:
HashMap<String,String> upper = new HashMap<>();
This means that both the key and value will be of type String. Thus, providing a valid key the the get() method will return a String:
String myValue = upper.get("blazer");
If you wish to check if a key is available before you attempt to read the value you can use the method containsKey() with will return a boolean value indicating whether the HashMap contains an entry with the given key:
if(upper.containsKey("blazer")){
String myValue = upper.get("blazer");
Log.e(TAG, "Yes blazer is available : " + myValue);
}
else{
Log.e(TAG, "No blazer is available!");
}
You can also iterate through the available keys like this:
Set<String> set = map.keySet();
for(String s : set){
Log.e(TAG, "Map key = " + s + " value = " + map.get(s));
}
They way you have it there upper.get(upper.get("blazer")); would just return null.
You're passing in upper.get("blazer") (which would return "both") to your outer upper.get. Since you have no "both" key stored in your map, it returns null.
Should be:
upper.get("blazer");
Related
I have a linked hash map which stores random 6 char string as a key and 30 char string as values. When I call replace method, it is supposed to replace value for given key and return existing value associated with given key.
Code
Map cache = new LinkedHashMap<String, String>();
protected boolean registerCache(String key, String val) {
System.out.println("Registering key "+ key +" associated with : "+val);
String result = cache.put(key, val);
System.out.println("Replacement result "+result);
return result == null;
}
protected synchronized boolean updateCache(String key, String val) {
System.out.println("map before replace : "+cache.toString());
String replaced = cache.replace(key, val);
System.out.println("replacing "+replaced+" with "+val);
return replaced != null;
}
Register cache stores key value for first time and then update method is supposed to replace value for registered key.
But once in 4 times, it fails to replace. It behaves as key was never registered. Here is output:
Registering key \b?}`& associated with : Vtw7vd3Mtk9DEImmZAxfazKrckVpt4
Replacement result null
map before replace: {
d\ZDO<=9pw7cEjdnvWhpbxar564kiSkVpt4Z1,
pHQ)j\=9pw7cEjdnvWhpbxar564kiSkVpt4Z1,
0''nEY=KxE7vdInrD2goNOU5LdMFdEMgsCh-1,
C\Gude=KxE7vdInrD2goNOU5LdMFdEMgsCh-1,
\b?}`&=Vtw7vd3Mtk9DEImmZAxfazKrckVpt4}
replacing null with KxE7vdInrD2goNOU5LdMFdEMgsCh-1
Please suggest if I am doing something wrong. I suspect the key generated should not be random char string.
I figured out reason.
As suggested by Thomas in comment above, I added more sysout for Keys against which value needs to be replaced.
I was using RandomStringUtils.randomAscii(6) (from commons library) for generating key. The key generated had some chars which were printed with spaces and hence the key was not properly found to replace value against it.
When I replaced RandomStringUtils.randomAscii(6) with RandomStringUtils.randomAlphanumeric(8), it's behaving as expected.
I have two linked hashmap (key - String, value = String[]) which got the same size and the same keys in both linked hashmaps, I want to be able to compare values according to the key, verifying values on one linked hashmap are equals to the same values in the second linked hashmap (by key) or at least the other linked hashmap contains the values.
I am populating both of the linked hashmaps with keys and values and set it to different linked hash maps.
Example for hashmap:
Key - alert - Value (array of strings)
0 - Device_UID,Instance_UID,Configuration_Set_ID,Alert_UID
1 - a4daeccb-0115-430c-b516-ab7edf314d35,0a7938aa-9a01-437f-88ac-4b2927ed7665,96,61b68069-9de7-4b85-83cb-8d9f558e8ecb
2 - a4daeccb-0115-430c-b516-ab7edf314d35,0a7938aa-9a01-437f-88ac-4b2927ed7665,12,92757faa-bf6b-4aa3-ba6d-2e57b44f333c
3 - a4daeccb-0115-430c-b516-ab7edf314d35,0a7938aa-9a01-437f-88ac-4b2927ed7665,369,779b3294-2ca3-4613-a413-bf8d4aa05d16
and it should be at least in the second linked hash- map
String rdsColumns="";
for(String key : mapServer.keySet()){
String[] value = mapServer.get(key);
String[] item = value[0].split(",");
rdsColumns="";
for(String val:item){
rdsColumns = rdsColumns.concat(val + ",");
}
rdsColumns = rdsColumns.concat(" ");
rdsColumns = rdsColumns.replace(", ", "");
info(("Query is: "+ returnSuitableQueryString(rdsColumns, key, alertId, deviceId)));
String query=returnSuitableQueryString(rdsColumns, key, alertId, deviceId);
mapRDS.put(key, insightSQL.returnResultsAsArray(query ,rdsColumns.split(","),rdsColumns));
}
where rdsColumns are the fields I am querying in RDS data-base.
Expected: iterating over both maps and verifying at that all values according to key in the first map contains or equal in the second map.
This is the code you are looking for:
for (String keys : firstMap.keySet()) {
String[] val1 = firstMap.get(keys);
String[] val2 = secondMap.get(keys);
if (Arrays.equals(val1, val2)) {
//return true;
}
ArrayList<Boolean> contains = new ArrayList<>();
for (int i = 0; i < val1.length; i++) {
for (String[] secondMapVal : secondMap.values()) {
List<String> list = Arrays.asList(secondMapVal);
if (list.contains(val1[i])) {
contains.add(true);
break;
} else contains.add(false);
}
}
if (contains.contains(true)) {
//return true; Even a single value matches up
} else {
//return false; Not even a sinle value matches up
}
}
Basically what we have here is a HashMap<String, String>. We take the set of keys and iterate through them. Then we take the value with the key from the two sets. After we got the values we compare them and if they are the same I just print that they match. You can change this and implement this with other types of HashMaps, even where you use custom values. If I didn't understand your problem tell me and I will edit the answer.
According to Java HashMap documentation, put method replaces the previously contained value (if any): https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html#put-K-V-
Associates the specified value with the specified key in this map. If
the map previously contained a mapping for the key, the old value is
replaced.
The documentation however does not say what happens to the (existing) key when a new value is stored. Does the existing key get replaced or not? Or is the result undefined?
Consider the following example:
public class HashMapTest
{
private static class Key {
private String value;
private Boolean b;
private Key(String value, Boolean b) {
this.value = value;
this.b = b;
}
#Override
public int hashCode()
{
return value.hashCode();
}
#Override
public boolean equals(Object obj)
{
if (obj instanceof Key)
{
return value.equals(((Key)obj).value);
}
return false;
}
#Override
public String toString()
{
return "(" + value.toString() + "-" + b + ")";
}
}
public static void main(String[] arg) {
Key key1 = new Key("foo", true);
Key key2 = new Key("foo", false);
HashMap<Key, Object> map = new HashMap<Key, Object>();
map.put(key1, 1L);
System.out.println("Print content of original map:");
for (Entry<Key, Object> entry : map.entrySet()) {
System.out.println("> " + entry.getKey() + " -> " + entry.getValue());
}
map.put(key2, 2L);
System.out.println();
System.out.println("Print content of updated map:");
for (Entry<Key, Object> entry : map.entrySet()) {
System.out.println("> " + entry.getKey() + " -> " + entry.getValue());
}
}
}
When I execute the following code using Oracle jdk1.8.0_121, the following output is produced:
Print content of original map:
> (foo-true) -> 1
Print content of updated map:
> (foo-true) -> 2
Evidence says that (at least on my PC) the existing key does not get replaced.
Is this the expected/defined behaviour (where is it defined?) or is it just one among all the possible outcomes? Can I count on this behaviour to be consistent across all Java platforms/versions?
Edit: this question is not a duplicate of What happens when a duplicate key is put into a HashMap?. I am asking about the key (i.e. when you use multiple key instances that refer to the same logical key), not about the values.
From looking at the source, it doesn't get replaced, I'm not sure if it's guaranteed by the contract.
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
It finds the existing mapping and replaces the value, nothing is done with the new key, they should be the same and immutable, so even if a different implementation can replace the key it shouldn't matter.
You can't count on this behavior but you should write your code in a way that it won't matter.
When a new pair is added, the map uses hasCode,equals to check if the key already present in the map. If the key already exists the old value is replaced with a new one. The key itself remains unmodified.
Map<Integer,String> map = new HashMap<>();
map.put(1,"two");
System.out.println(map); // {1=two}
map.put(1,"one");
System.out.println(map); // {1=one}
map.put(2,"two");
System.out.println(map); // {1=one, 2=two}
There is an issue with your equals and hashCode contract. ke1 and key2 are identical according to your implementation:
#Override
public boolean equals(Object obj)
{
if (obj instanceof Key)
{
return value.equals(((Key)obj).value);
}
return false;
}
you need to compare Boolean b as well
Key other = (Key) obj;
return value.equals(other.value) && b.equals(other.b);
The same rule apples to hasCode
#Override
public int hashCode()
{
return value.hashCode();
}
return value.hashCode() + b.hashCode();
with these changes key1 and key2 are different
System.out.println(key1.equals(key2));
and the output for your map will be
> (foo-true) -> 1
> (foo-false) -> 2
It is not replaced - neither it should. If you know how a HashMap works and what hashCode and equals is (or more precisely how they are used) - the decision of not touching the Key is obvious.
When you put the other Key/Entry in the map for the second time, that key is first look-up in the map - according to hashCode/equals, so according to the map IFF keys have the same hashCode and are equal according to equals they are the same. If so, why replace it? Especially since if it would have been replaced, that might rigger additional operations or at least additional code to not trigger anything else if keys are equal.
Apparently the current HashSet implementation relies on this HashMap behaviour in order to be compliant to the HashSet documentation.
With that i mean that when you add a new element in an HashSet the documentation says that if you try to add an element in an HasSet that already contains the element, the HashSet is not changed and so the element is not substituted,
In the openjdk8 implementation the HashSet uses an HashMap keys to hold the values and in the HashSet.add method it calls the HashMap.put method to add the value, thus relying on the fact that the put method will not substitute the object
Although this still not a direct specification in the documentation and it's subject to variations in the JRE implementation, it probably provides a stronger
assurance that this will probably not change in the future
I have a very weird behavior in a Java program. I have a Long, Long hashmap, retrieved from a method but when I tried to get the information from it, this hashmap is a String, String without any errors nor warnings.. Below my code:
List<HashMap<Long, Long>> getAggregateResult(String idCheptel, Integer limit) {
StringBuilder hql = new StringBuilder();
hql.append("select new map(t.prod.id, count(t.prod.id))");
... //rest of implem.
return entityManager.createQuery(hql.toString()).setMaxResults(limit).getResultList();
}
Call of the function
... //in other method try to retrieve the information
for (HashMap<Long, Long> map : getAggregateResultVetProduct(idCheptel, limit)) {
System.out.println(">>>>>>>" + map.get(0L)); //always null
//the map is asked in Long, but in debugger it's a String, String
for (Map.Entry<Long, Long> entry : map.entrySet()) {
System.out.println("Key: " + entry.getKey()); //here key are 0
System.out.println("Value: " + entry.getValue());
}
}
If someone could give me some information why there is this behavior. Thanks.
Edit
Here some information:
I am using Intellij. And below the screen shot of the debugger, since it was asked.
Information about generics are erased during compilation. So during the runtime your method returns just HashMap. So the interesting question is what is real type of the return value of .getResultList() method.
so basically, I'm trying to parse through each map entry of a HashMap while also reading each string value in the String array. I will then use each of those string values in the array as parameters for specific methods. Now, I know how to parse through each map entry, it's just the iterating through the string array in the map that's confusing me. Any advice?
My code:
HashMap<String,String[]> roomSite = new HashMap<String, String[]>();
Set set = roomSite.entrySet();
Iterator<Map.Entry<String, String[]>> iterator = set.iterator();
while(iterator.hasNext()) {
Map.Entry mentry = (Map.Entry)iterator.next();
System.out.print("key is: "+ mentry.getKey() + " & Value is: ");
System.out.println(Arrays.deepToString((String[]) mentry.getValue()));
}
Output:
key is: 0 & Value is: [wall, d0, wall, wall]
key is: 1 & Value is: [d0, wall, d1, wall]
key is: 2 & Value is: [wall, wall, wall, d1]
You already have the String array, just assign it to a variable:
String[] stringArray = (String[]) mentry.getValue();
for (String str : stringArray){
// process str
}
Solution using Java 8 stream feature
HashMap<String,String[]> roomSite = new HashMap<>();
roomSite.put("1",new String[]{"Hello","World"});
roomSite.put("2",new String[]{"India","Germany"});
//This is to print all value for given key but if you want process for each key with all value then put ur logic into forEach
roomSite.entrySet().stream().map(entry -> "key is: "+entry.getKey() + " & Value is: " + Arrays.stream(entry.getValue())
.collect(Collectors.joining(","))).forEach(System.out::println);
//This logic emits entry for key and value from array, basically you will have pair of key and value which can be used for processing
roomSite.entrySet().stream().flatMap(entry-> Arrays.stream(entry.getValue()).map(value->new AbstractMap.SimpleEntry<>(entry.getKey(),value))).forEach(simpleEntry-> {
final String key= simpleEntry.getKey();
final String value= simpleEntry.getValue();
System.out.println("Key : "+ key+" , value : "+ value);
//process ur logic
});