I have written following code which is resulting in concurrent modification exception. How can I prevent it ? The idea is to escape all values of the Map and reconstruct the object (dO) back with new param map.
try {
Map<String,String[]> paramMap = dO.getParameterMap();
Set<Map.Entry<String, String[]>> entries = paramMap.entrySet();
Iterator<Map.Entry<String, String[]>> it = entries.iterator();
while (it.hasNext()) {
Map.Entry<String, String[]> entry = it.next();
String[] values = entry.getValue();
List<String> valList = new ArrayList<String>();
if (values != null) {
for (String value : values) {
valList.add(escapeHTML(value));
}
dO.removeParameter(entry.getKey());
//Please note that Parameter is a hashMap so , Is it required to remove the entry first before inserting or it will replace the new value associated with key . How it works in Java ?
dO.addParameter(entry.getKey(),valList.toArray(new String[valList.size()]));
}
}
}
the exception is thrown because you are adding/removing things from the map while you are iterating it:
dO.removeParameter(entry.getKey());
dO.addParameter(entry.getKey(),valList.toArray(new String[valList.size()]
you should use iterator.remove() instead.
Not sure you need to alter the keys of Map, it appears all you want to do is alter the values in the arrays.
for(String[] values: dO.getParameterMap().values())
for (int i = 0; i < values.length; i++)
values[i] = escapeHTML(values[i]);
I would make sure the Map does have null values stored. But if you can't change this you will need to add if(values != null)
You should remove/add only if you are changing a key in a map. As I see in the code, you are changing only value. Hence you could use entry.setValue(...) instead.
ConcurrentModificationException is thrown when you use fail-fast iterators (eg: entries.iterator() is fail-fast iterator). What they do is they iterate over original collection object.
To be able to modify and iterate over a collection object you can use fail-safe iterator (eg: List<Book> books = new CopyOnWriteArrayList<>()) This will take a copy inside memory while iterating over the elements and even you will be able to modify it.
Related
I want to remove a specific value from the hashmap and the key from that value. Look, for example if I have
hashMap.put(cold, frozen)
hashMap.put(cold,hard)
, in my graphic interface i will have cold=[frozen,hard].If I want to erase hard I want cold = [frozen] to stay
My hashMap is private HashMap<String,ArrayList<String>> hashMap ;
Here is what I tried but it's not good enough because if I have at 2 different key the value i want to remove, it only removes the value for the first and if I have for ex cold=[frozen,hard] and I erase hard it doesn't keep cold=[frozen];
for(String key : hashMap.keySet()){
int siz = hashMap.get(key).size();
for(int i = 0; i< siz;i++){
if(hashMap.get(key).get(i).equals(cuvant)){
s.remove(hashMap.get(key).get(i));
siz--;
hashMap.remove(key);
}
}
}
I forgot to mention that s is the arrayList with the values.
Are you putting an ArrayList with the values in a hashmap?
If so, then check for list size first:
if (! hashMap.get(key).isEmpty()){
hashMap.get(key).remove(ValueToRemoved)
}
add a condition
if (hashMap.get(key).isEmpty())
before
hashMap.remove(key);
This will ensure you delete a key only if the list associated with it is completely empty.
Also, make sure you do NOT keep iterating (the inner loop) after removing an element from the list if you use a for-each loop, it will get you a ConcurrentModificationException. If your list can have the same value multiple times (and should be removed multiple times), use the Iterator API rather than for-each loop.
Try this :-
HashMap<String, ArrayList<String>> m = new HashMap<>();
Iterator<Map.Entry<String,ArrayList<String>>> iter = m.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry<String,ArrayList<String>> entry = iter.next();
ArrayList<String> list = entry.getValue();
for(int i = 0 ; i < list.size() ; i++){
if(list.get(i).equals(cuvant)){
list.remove(i);
}
}
if(list.isEmpty())
iter.remove();
}
Here's some code:
ArrayList<String> List = new ArrayList<>();
Map<String, List<String> > map = new HashMap<String, List<String>>();
List.add("stringA");
List.add("stringB");
List.add("stringC");
for(int i = 0; i<List.size();i++){
String key = List.get(i);
List<String> value = new ArrayList<String>();
map.put(key, value);
}
This code takes whatever is in the ArrayList, loops through it, adds it to the Map, and then creates an empty ArrayList with each string name as the variable name. Now, this works, but there's one problem, unless I'm overlooking something. At some point, I will need to access the new empty ArrayLists that are in the map. However, I won't know what the titles of these ArrayLists are, without printing them out, which I don't want to do. Basically, I'm thinking I need a map method or class and then an additional map key method or class. I'm not sure how to implement it but maybe something like this:
public class MapKey {
public MapKey(int count, String header){
}
}
Map<MapKey, List<String> > map = new HashMap<MapKey, List<String>>();
Another option I've considered is to somehow loop through the map array and add Strings to each ArrayList, but I'm very new to maps and looping through them. Especially ones that contain ArrayLists as their values.
There're multiple ways to access keys and values of your HashMap:
for (Map.Entry<String,ArrayList<String>> entry : map.entrySet()) {
String key = entry.getKey();
ArrayList<String> value = entry.getValue();
// do your work
}
or
Set<String> keys = map.keySet();
for(String key : keys){
ArrayList<String> value = map.get(key);
}
Read the java HashMap api Java HashMap Link
Edit:
you dont need to loop through your outside ArrayList objects when you add all of its elements to another, just simply invoke addAll(), it will append all elements of an arraylist to another.
ArrayList<String> aList = map.get("stringA");
assume your first outside ArrayList is called outListOne;
aList.addAll(outListOne);
Appends to corresponding lists:
//assume number of outside lists are equal to number of map elements
String[] keysArr = {"stringA", "stringB", "stringC"};
ArrayList[] outLists = {outListOne, outListTwo, outListThree};
// adds outside lists to corresponding map ArrayList lists
for(int i = 0; i < keysArr.length; i++){
list = map.get(keysArr[i]); // you ArrayList in a map, get it by key name
list.addAll(outLists[i]); // append elements from out list to corresponding list
}
Not exactly sure what you mean by "titles of these ArrayLists." But here are a few code snippets that might give you a better idea of how to work with your map:
// add string x to the list for "stringA"
map.get("stringA").add(x);
// print all the values in the list for "stringC"
for (String s: map.get("stringC")) {
System.out.println(s);
}
// print the names of the lists that contain "xyzzy"
for (String key: map.keySet()) {
if (map.get(key).contains("xyzzy")) {
System.out.println(key);
}
}
// remove "foo" wherever it appears in any of the lists
for (List<String> list: map.values()) {
while (list.remove("foo")){}
}
The following code works fine when there are more than one modification in a particular map. But when there is only one modification it throws concurrent modification exception
for(Map.Entry<String, List<String>> mapEntry : beanMap.entrySet()) {
for(String dateSet : dateList) {
String mName = mapEntry.getKey();
boolean dateFound = false;
if(beanMap.containsKey(dateSet)) {
dateFound = true;
System.out.println(" Found : "+mapEntry.getKey());
}
if(!dateFound)
{
Map<String, List<String>> modifiedMap = beanMap;
List<String> newBeanList = new ArrayList<String>();
dBean beanData = new Bean(dateSet+"NA","NA","NA",0,0,0);
newBeanList.add(beanData);
System.out.println(" Adding : "+dateSet+" "+"NA");
modifiedMap.put(mName, newBeanList);
}
}
}
In the above code it throws ConcurrentModificationException when modifying the "modifiedMap" only once. May be there is more to it but couldn't find out why.
When you use an enhanced for loop, there is an implicit Iterator working behind the scenes. You attempt to make a copy of beanMap with this line:
Map<String, List<String>> modifiedMap = beanMap;
However, this only creates another reference variable that also refers to the same map object. There is still only one map, and you are modifying it:
modifiedMap.put(mName, newBeanList);
The Iterator then detects that the map is modified when it attempts to iterate to the next entry, resulting in the ConcurrentModificationException.
You can create another Map with new, and put all your modifications into that map while you're iterating the original map.
After you're done iterating the original map, you can call the putAll method on it, passing your new map, to apply all of the modifications you want.
You are not allowed to change the underlying collection while iterating over it using this syntax. The collections are implemented in a fail-fast way, so even a single change will raise the exception.
If you need to change the collection while visiting the elements, use an Iterator.
modifiedMap is the reference to same Map beanMap on which you are iterating. You are modifying the Collection modifiedMap while iteration hence the Exception.
In a HashMap
map = new HashMap<String,String>();
it = map.entrySet().iterator();
while (it.hasNext())
{
entry = it.next();
it.remove(); //safely remove a entry
entry.setValue("new value"); //safely update current value
//how to put new entry set inside this map
//map.put(s1,s2); it throws a concurrent access exception
}
When i trying to add a new entry to map it throws ConcurrentModificationException. For remove and update iterator has safely removing methods. How to add new entry while iterating?
You need to consider what it means to put a value to a Map whilst iterating. HashMap defines no order over which its entries will be iterated over. So when you put a new entry, should the entry be returned by the iterator later or not. Consistency of behaviour is important. However, whichever way you decide you'll get inconsistent behaviour when you put a new value to a preexisting key. If the key has already been iterated over then the change won't appear and will appear if the key has yet to be produced by the iterator.
A simple way to overcome this problem is to create a temporary Map of the new key-value pairs and add the temporary Map to the main Map at the end of your iteration.
Map<String,String> values = ...
Map<String,String> temp = new HashMap<>();
for (Entry<String,String> entry : values.entrySet()) {
if ("some value".equals(entry.getValue()) {
temp.put(entry.getValue(), "another value");
}
}
values.putAll(temp);
You need to use ConcurrentHashMap to add elements while iterating the collection. HashMap uses fail-fast iterator, which throws ConcurrentModificationException when the collection is updated while iterating. Whereas ConcurrentHashMap uses fail-safe iterator, which basically works on the clone of the underlying collection and hence allows modification while iterating.
How about:
map = new HashMap<String,String>();
it = map.entrySet().iterator();
while (it.hasNext())
{
entry = it.next();
entry.setValue("new value"); // update current value
}
I checked the HashMap implementation, it does not change its modification count when updating an entry like this. I also see no reason why this shouldn't be allowed. Nothing is removed, nothing is added and no keys are changed.
What I did was to create an array with the current elements and then iterate through the array:
Feature[] initialFeatures = featureMap.values().toArray(new Feature[featureMap.values().size()]);
for (Feature feature : initialFeatures)
{/* Code that can safely add to the featureMap */}
I am working on a logic , on a list of type String.
All , I am looking for is removing the duplicate element in the list. I am little buzzed what going wrong. As it is comparing the same index level element.
List<Favorite> queueFavorites = retrieve();
// Removing the duplicate favorite
for (Iterator<Favorite> favoriteIterator = queueFavorites.iterator(); favoriteIterator.hasNext(); )
{
FavoriteBO favoriteBO = favoriteIterator.next();
if(duplicateCount(queueFavorites,favoriteBO) > 1)
{
favoriteIterator.remove();
System.out.println("Favorite Removed : " + favoriteBO.getFavoriteUID());
}
}
I have overridden Favorite class method like hashCode and equals. This means I need to make use of duplicateCount () method.
Any suggestion would be helpful.
Thanks !!!
Use Set instead of List which stores only unique value and implement HashSet instead of ArrayList.
Try Set mySet = new HashSet(List);
To convert List to Set
Or else
Use contains method and remove the object if it is already present in List so that order is maintained
Java had Set for this kind of things....so you should populate a set instead of a list...but if is not your case and you have an external list you can create a Set impl (e.g. HashSet) giving your list in the constructor
Set noDups = new HashSet (yourList);
Et voilÄ
Another approach to the problem instead of using Set is to use a map:
HashMap<String, Object> map = new HashMap<String, Object>();
Iterator<String> it = queueFavorites.iterator();
while (it.hasNext()) {
String str = (String) it.next();
if(map.get(str) != null) {
it.remove();
}
else {
map.put(str, new Object());
}
}
This approach preserves your List elements and only removes the duplicates