Removing items from a list [duplicate] - java

This question already has answers here:
Getting a ConcurrentModificationException thrown when removing an element from a java.util.List during list iteration? [duplicate]
(11 answers)
Closed 9 years ago.
While looping through a list, I would like to remove an item of a list depending on a condition. See the code below.
This gives me a ConcurrentModification exception.
for (Object a : list) {
if (a.getXXX().equalsIgnoreCase("AAA")) {
logger.info("this is AAA........should be removed from the list ");
list.remove(a);
}
}
How can this be done?

for (Iterator<String> iter = list.listIterator(); iter.hasNext(); ) {
String a = iter.next();
if (...) {
iter.remove();
}
}
Making an additional assumption that the list is of strings.
As already answered, an list.iterator() is needed. The listIterator can do a bit of navigation too.
–---------
Update
As #AyushiJain commented, there is
list.removeIf(...);

You need to use Iterator and call remove() on iterator instead of using for loop.

You cannot do it because you are already looping on it.
Inorder to avoid this situation use Iterator,which guarentees you to remove the element from list safely ...
List<Object> objs;
Iterator<Object> i = objs.iterator();
while (i.hasNext()) {
Object o = i.next();
//some condition
i.remove();
}

You can't and shouldn't modify a list while iterating over it. You can solve this by temporarely saving the objects to remove:
List<Object> toRemove = new ArrayList<Object>();
for(Object a: list){
if(a.getXXX().equalsIgnoreCase("AAA")){
toRemove.add(a);
}
}
list.removeAll(toRemove);

Besides all the excellent solutions offered here I would like to offer a different solution.
I'm not sure if you're free to add dependencies, but if you can, you could add the https://code.google.com/p/guava-libraries/ as a dependency. This library adds support for many basic functional operations to Java and can make working with collections a lot easier and more readable.
In the code I replaced the type of the List by T, since I don't know what your list is typed to.
This problem can with guava be solved like this:
List<T> filteredList = new Arraylist<>(filter(list, not(XXX_EQUAL_TO_AAA)));
And somewhere else you then define XXX_EQUAL_TO_AAA as:
public static final Predicate<T> XXX_EQUAL_TO_AAA = new Predicate<T>() {
#Override
public boolean apply(T input) {
return input.getXXX().equalsIgnoreCase("AAA");
}
}
However, this is probably overkill in your situation. It's just something that becomes increasingly powerful the more you work with collections.
Ohw, also, you need these static imports:
import static com.google.common.base.Predicates.not;
import static com.google.common.collect.Collections2.filter;

//first find out the removed ones
List removedList = new ArrayList();
for(Object a: list){
if(a.getXXX().equalsIgnoreCase("AAA")){
logger.info("this is AAA........should be removed from the list ");
removedList.add(a);
}
}
list.removeAll(removedList);

Related

Collision Detection returns ConcurrentModificationException [duplicate]

This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 8 years ago.
I'm trying to remove some elements from an ArrayList while iterating it like this:
for (String str : myArrayList) {
if (someCondition) {
myArrayList.remove(str);
}
}
Of course, I get a ConcurrentModificationException when trying to remove items from the list at the same time when iterating myArrayList. Is there some simple solution to solve this problem?
Use an Iterator and call remove():
Iterator<String> iter = myArrayList.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}
As an alternative to everyone else's answers I've always done something like this:
List<String> toRemove = new ArrayList<String>();
for (String str : myArrayList) {
if (someCondition) {
toRemove.add(str);
}
}
myArrayList.removeAll(toRemove);
This will avoid you having to deal with the iterator directly, but requires another list. I've always preferred this route for whatever reason.
Java 8 user can do that: list.removeIf(...)
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
list.removeIf(e -> (someCondition));
It will remove elements in the list, for which someCondition is satisfied
You have to use the iterator's remove() method, which means no enhanced for loop:
for (final Iterator iterator = myArrayList.iterator(); iterator.hasNext(); ) {
iterator.next();
if (someCondition) {
iterator.remove();
}
}
No, no, NO!
In single threated tasks you don't need to use Iterator, moreover, CopyOnWriteArrayList (due to performance hit).
Solution is much simpler: try to use canonical for loop instead of for-each loop.
According to Java copyright owners (some years ago Sun, now Oracle) for-each loop guide, it uses iterator to walk through collection and just hides it to make code looks better. But, unfortunately as we can see, it produced more problems than profits, otherwise this topic would not arise.
For example, this code will lead to java.util.ConcurrentModificationException when entering next iteration on modified ArrayList:
// process collection
for (SomeClass currElement: testList) {
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
}
}
But following code works just fine:
// process collection
for (int i = 0; i < testList.size(); i++) {
SomeClass currElement = testList.get(i);
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
i--; //to avoid skipping of shifted element
}
}
So, try to use indexing approach for iterating over collections and avoid for-each loop, as they are not equivalent!
For-each loop uses some internal iterators, which check collection modification and throw ConcurrentModificationException exception. To confirm this, take a closer look at the printed stack trace when using first example that I've posted:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at TestFail.main(TestFail.java:43)
For multithreading use corresponding multitask approaches (like synchronized keyword).
While other suggested solutions work, If you really want the solution to be made thread safe you should replace ArrayList with CopyOnWriteArrayList
//List<String> s = new ArrayList<>(); //Will throw exception
List<String> s = new CopyOnWriteArrayList<>();
s.add("B");
Iterator<String> it = s.iterator();
s.add("A");
//Below removes only "B" from List
while (it.hasNext()) {
s.remove(it.next());
}
System.out.println(s);
If you want to modify your List during traversal, then you need to use the Iterator. And then you can use iterator.remove() to remove the elements during traversal.
List myArrayList = Collections.synchronizedList(new ArrayList());
//add your elements
myArrayList.add();
myArrayList.add();
myArrayList.add();
synchronized(myArrayList) {
Iterator i = myArrayList.iterator();
while (i.hasNext()){
Object object = i.next();
}
}
One alternative method is convert your List to array, iterate them and remove them directly from the List based on your logic.
List<String> myList = new ArrayList<String>(); // You can use either list or set
myList.add("abc");
myList.add("abcd");
myList.add("abcde");
myList.add("abcdef");
myList.add("abcdefg");
Object[] obj = myList.toArray();
for(Object o:obj) {
if(condition)
myList.remove(o.toString());
}
You can use the iterator remove() function to remove the object from underlying collection object. But in this case you can remove the same object and not any other object from the list.
from here

Java. How to delete duplicate objects from both Lists

2nd question, which is continue of first.
I have got two Lists of strings. There is an List of strings (asu) - M1, M2, M3 ... As well as an List of string (rzs) - M1, M2, M3 and all possible combinations thereof. The need for each element (asu) (for example M1) to find an element in (rzs) (M1, M1M2, ..), which contains (e.g. M1). Example: took M1 from (asu) and will start search for duplicate(contain) in (rzs). We found M1M2 in (rzs), it contains M1. After that we should delete both elements from lists. Great thanks to No Idea For Name helped for modification this code. But the program always fails because AbstractList.remove error. Please help to implementation logic and tuning code!
Imports..........
public class work{
List<string> asu = Arrays.asList("M1","M1","M1","M3","M4","M5","M1","M1","M1","M4","M5","M5");
List<string> rzs = Arrays.asList("M1","M2","M3","M4","M5",
"M1M2","M1M3","M1M4","M1M5","M2M3","M2M4","M2M5","M3M4","M3M5","M4M5"
,"M1M2M3","M1M2M4","M1M2M5","M1M3M4","M1M3M4","M1M4M5","M2M4","M2M5");
public static void main(String[] args) {
work bebebe = new work();
bebebe.mywork();
}
List<string> tmp1 = new ArrayList<string>();
List<string> tmp2 = new ArrayList<string>();
System.out.println(Arrays.deepToString(rzs));
System.out.println(Arrays.deepToString(asu));
for (string curr : asu){
for (string currRzs : rzs){
System.out.println("New iteration ");
if (currRzs.contains(curr)) {
System.out.println("Element ("+curr+") in ASU =
element ("+currRzs+") in RZS");
if(tmp1.contains(curr) == false)
tmp1.add(curr);
if(tmp2.contains(currRzs) == false)
tmp2.add(currRzs);
}
}
}
for (string curr : tmp1){
asu.remove(curr);
}
for (string currRzs : tmp2){
rzs.remove(currRzs);
}
You should try to make use of removeAll() or retainAll() methods of Collection.
For example:
List<String> aList = new ArrayList<String>();
aList.add("a");
aList.add("b");
aList.add("c");
aList.add("d");
aList.add("e");
List<String> bList = new ArrayList<String>();
bList.add("b");
bList.add("e");
bList.add("d");
aList.removeAll(bList);
will give you the "a" and "c" elements left in aList
While if you try to make use of retainAll() method:
aList.retainAll(bList);
will give you "b", "d" and "e" elements left in aList;
retainAll() is used to remove all the elements of the invoking collection which are not part of the given collection.
removeAll() is used to remove all the elements of a collection from another collection.
So, it all depends on your use-case.
EDIT
If in any case you want to remove some elements from these collections while iterating conditionally then you should first obtain the Iterator<Type> then call the remove() method over it.
Like:
while(iterator.hasNext()){
String str = iterator.next();
if(str.equals('test')){
iterator.remove();
}
}
Don't remove items from list using foreach loop. Use classic for and iterate over elements, and when removing item, decrease iterator.
To safely remove elements while iterating use Iterator.remove method:
The behavior of an iterator is unspecified if the underlying
collection is modified while the iteration is in progress in any way
other than by calling this method.
Iterator<String> i = tmp1.iterator();
while (i.hasNext()) {
i.next(); // must be called before remove
i.remove();
}
Also it is easier to remove all collection from another by simply calling:
asu.removeAll(tmp1);
instead of List you can use Set, which will remove automatically the duplicate elements...
You can use removeAll() method to remove collection of elements from the list instead of removing one by one.
use
asu.removeAll(tmp1);
instead of
for (string curr : tmp1)
{
asu.remove(curr);
}
and use
rzs.removeAll(tmp2);
instead of
for (string currRzs : tmp2)
{
rzs.remove(currRzs);
}
update
I trace out your problem.The problem lies in Arrays.asList() method.
According to Arrays#asList
asList() returns "a fixed-size list backed by the specified array". If you want to resize the array, you have to create a new one and copy the old data. Then the list won't be backed by the same array instance.
So create a duplicate ArrayList for the lists.Like this
List<string> asuDuplicat = new ArrayList<string>(asu);
List<string> rzsDuplicat = new ArrayList<string>(rzs);
use asuDuplicat,rzsDuplicat.
asuDuplicat.removeAll(tmp1);
rzsDuplicat.removeAll(tmp2);

ConcurrentModificationException In a Java BO

I am getting a java.util.ConcurrentModificationException in this code and can't seem to understand why, or fix it.
In the BO I have this (privileges is an arraylist inside the BO)
public void setPrivilegename(String privilegename) {
this.privileges.add(privilegename);
}
List<PrivilegeObjectBO> arraylist = new ArrayList<PrivilegeObjectBO>();if (rs != null) {
while (rs.next()) {
for (BO bo : arraylist) {
if (bo.getRolepkey()==rs.getInt("ROLE_PKEY")) {
bo.setPrivilegename(rs.getString("SP.NAME"));
}else{
BO newobj = new BO();
newobj.setRolepriviledgepkey(rs.getInt("PRIVILEGE_PKEY"));
newobj.setProticolpkey(protocol);
newobj.setPrivilegename(rs.getString("SP.NAME"));
newobj.setRolepkey(rs.getInt("SRP.ROLE_PKEY"));
arraylist.add(newobj);
}
}
}
}
As per ArrayList javadoc
The iterators returned by this class's iterator and listIterator
methods are fail-fast: if the list is structurally modified at any
time after the iterator is created, in any way except through the
iterator's own remove or add methods, the iterator will throw a
ConcurrentModificationException.
for (BO bo : arraylist)
Above for-each loop gets Iterator for the list and
arraylist.add(newobj);
You are trying to modify the list without using iterators own methods, which results in ConcurrentModificationException
Here is SO discussion on possible solutions.
In java, you will always get a ConcurrentModificationException when you modify the Collection while you are iterating over it.
Possible solution: use a temporary Collection for added or deleted items, and add or delete those items after the iteration is done.
You cannot iterate over ArrayList and add elements to it at the same time with foreach.
Use iterator, like this:
Iterator<PrivilegeObjectBO> iterator = arraylist.iterator();
while (iterator.hasNext()) {
...
}
Others have already pointed out that add-ing to an ArrayList while iterating over it is disallowed.
But to solve your problem anyway, it looks like you need to iterate over the entire list before attempting to add to it, because it your loop appears to be checking to see if anything in the list matches your row to avoid duplicates. In this case you don't want to add to the list while iterating over it because you don't know whether the list has a duplicate until the end.
So just iterate through and check to see if a match is found:
List<PrivilegeObjectBO> arraylist = new ArrayList<PrivilegeObjectBO>();
if (rs != null) {
while (rs.next()) {
boolean found = false;
for (BO bo : arraylist) {
if (bo.getRolepkey() == rs.getInt("ROLE_PKEY")) {
bo.setPrivilegename(rs.getString("SP.NAME"));
found = true;
}
}
if (!found) {
BO newobj = new BO();
newobj.setRolepriviledgepkey(rs.getInt("PRIVILEGE_PKEY"));
newobj.setProticolpkey(protocol);
newobj.setPrivilegename(rs.getString("SP.NAME"));
newobj.setRolepkey(rs.getInt("SRP.ROLE_PKEY"));
arraylist.add(newobj);
}
}
}
Unless you really do want to add a new BO for every non-matching BO already in the list...
Maybe you can take a look at Collections.synchronizedList(List<?>) static method.
It should return a thread safe List from the List object given, and you should not get the exception anymore.
Otherwise, you could try (if applicable) to set the method that accesses to the list synchronized, by adding the keyword synchronized in the method declaration.

Getting a ConcurrentModificationException thrown when removing an element from a java.util.List during list iteration? [duplicate]

This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 5 years ago.
#Test
public void testListCur(){
List<String> li=new ArrayList<String>();
for(int i=0;i<10;i++){
li.add("str"+i);
}
for(String st:li){
if(st.equalsIgnoreCase("str3"))
li.remove("str3");
}
System.out.println(li);
}
When I run this code,I will throw a ConcurrentModificationException.
It looks as though when I remove the specified element from the list, the list does not know its size have been changed.
I'm wondering if this is a common problem with collections and removing elements?
I believe this is the purpose behind the Iterator.remove() method, to be able to remove an element from the collection while iterating.
For example:
Iterator<String> iter = li.iterator();
while(iter.hasNext()){
if(iter.next().equalsIgnoreCase("str3"))
iter.remove();
}
The Java 8 way to remove it from the List without Iterator is:
li.removeIf(<predicate>)
i.e.
List<String> li = new ArrayList<String>();
// ...
li.removeIf(st -> !st.equalsIgnoreCase("str3"));
Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will thow this exception
Taken from http://download.oracle.com/javase/1.4.2/docs/api/java/util/ConcurrentModificationException.html
yes people run into it -- the problem is you can't modify the list while iterating over it. I have used 2 alternatives in the past:
You can keep track of the indexes of the items you want to remove, and then remove them after you are done iterating.
Or you can copy all the ones you want to keep into a new list as you iterate, and then discard the old list when done.
those options assume you have to iterate over the list to find the elements to remove -- useful in cases where the list elements are complex objects with properties you might test on.
In your particular case, you dont even need to iterate, as you can just use removeAll. Look at the API here. There are also nifty methods like retainAll that discard everything that is not in the argument. You can use remove/retain-like methods whenever the objects in the list implement equals and hashcode properly. If you cannot rely on equals/hashcode to identify equality between instances in your app, you will have to do the removal yourself....
Try this (Java 8):
list.removeIf(condition);
You could make a copy of list you want to remove element from, directly in for-each loop. For me, that is the simpliest way. Something like this:
for (String stringIter : new ArrayList<String>(myList)) {
myList.remove(itemToRemove);
}
Hope that will help you..
I think it is worth mentioning the Java 8 version
#Test
public void testListCur() {
List<String> li = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
li.add("str" + i);
}
li = li.stream().filter(st -> !st.equalsIgnoreCase("str3")).collect(Collectors.toList());
System.out.println(li);
}
ArrayList has field modCount - count of collection modifications
When you invoke method iterator() creates new object Itr. It has field expectedModCount. expectedModCount field initialize by modCount value. When you invoke
li.remove("str3");
modCount increments. When do you try access to li via iterator
checks that expectedModCount == modCount
and if it is false throws ConcurrentModificationException
Hence if you get iterator and after collection modified - iterator is considered not valid and you cannot use it.
I think that best answer is from bigdev.de, but i would like to add something to it(like if the item is removed from a list, maybe you would like to log that somewhere or something):
List<String> list = new ArrayList<>();
list.removeIf(a -> {
boolean condition = a.equalsIgnoreCase("some condition");
if(condition)
logger.info("Item removed from the list: " + a);
return condition;
});
I got this problem and I think the easier way is the same with the second way that hvgotcodes gave.
Or you can copy all the ones you want to keep into a new list as you iterate, and then discard the old list when done.
#Test
public void testListCur(){
List<String> li=new ArrayList<String>();
for(int i=0;i<10;i++){
li.add("str"+i);
}
List<String> finalLi = new ArrayList<String>();
for(String st:li){
if(st.equalsIgnoreCase("str3")){
// Do nothing
} else {
finalLi.add(st);
}
}
System.out.println(finalLi);
}
I looped a different way...
public void testListCur(){
List<String> li=new ArrayList<String>();
for(int i=0;i<10;i++){
li.add("str"+i);
}
for(int i=0; i<li.size(); i++)
if(li.get(i).equalsIgnoreCase("str3"))
li.remove(i--);
System.out.println(li);
}

Can we use for-each loop for iterating the objects of Iterator type? [duplicate]

This question already has answers here:
Idiomatic way to use for-each loop given an iterator?
(9 answers)
Closed 3 years ago.
If we do the following we get error:
class FGH{
public static Iterator reverse(List list) {
Collections.reverse(list);
return list.iterator();
}
public static void main(String[] args) {
List list = new ArrayList();
list.add("1"); list.add("2"); list.add("3");
/*for(Iterator it:reverse(list))
Iterator it=reverse(list);*/
for (Object obj: reverse(list))
System.out.print(obj + ", ");}}
but if we modify the code like this we don't get error,so is it mean that we can't iterate the objects of Iterator type? :
class FGH{
public static Iterator reverse(List list) {
Collections.reverse(list);
return list.iterator();
}
public static void main(String[] args) {
List list = new ArrayList();
list.add("1"); list.add("2"); list.add("3");
Iterator it=reverse(list);
while(it.hasNext()){
Object obj=it.next();
System.out.println(obj);
}
}}
A lot of answers talk about how iterators are not iterables. That's true, but such an answer doesn't touch on why.
The reason for-each loops require an iterable is to allow the same object to be traversed multiple times (so that you can use multiple for-each loops over the same object without surprising behaviour), whereas an iterator only allows one traversal. If for-each allowed iterators to be used, the behaviour would be surprising to programmers who didn't realise that their iterators would be exhausted after the loop is run.
If you're using an API that only gives you iterators, and you want to use iterables, you have two ways to solve this:
Make an anonymous iterable class, whose iterator() method calls the API function that returns the iterator. That way, each time you use a for-each loop on the iterable object, that API function is called again, returning a new (and unexhausted) iterator.
Make a one-pass iterable wrapper class that takes an iterator and allows one call to iterator(). On subsequent calls, throw an AssertionError or IllegalStateException as appropriate.
The for loop in your first example expects that reverse(list) is a collection of Iterator, which of course it isn't. That's why that example won't work.
In general, you can only use foreach on classes that implement Iterable. Iterator is not one of these classes.
See http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Iterable.html
You would have to wrap your Iterator in an Iterable first. Here's a Java 8 solution:
for (Object obj : (Iterable<Object>) () -> reverse(list))
System.out.print(obj + ", ");
Or, just use Iterator.forEachRemaining():
reverse(list).forEachRemaining(obj -> System.out.print(obj + ", "));
You'd use the enhanced for loop in this way:
for (Object o : list)
As pointed out above, you need to reference an Iterable (or array) in a for-each block. For example, when you do the following:
Collection<String> coll = ...;
for (String str : coll) {
...
}
The following is really happening:
Collection<String> coll = ...;
for (Iterator<String> iter = coll.iterator(); iter.hasNext(); ) {
String str = iter.next();
}
In order to be able to do this, the argument has to implement Iterable (e.g. have a public iterator() method that returns an Iterator (or be an array). So your code should look like the following:
class FGH {
public static void main(String[] args) {
List list = new ArrayList();
list.add("1"); list.add("2"); list.add("3");
while (Object obj : Collections.reverse(list)){
System.out.println(obj);
}
}
}
The "for each" syntax is designed for collections (Iterable to be precise), not for Iterators. I'm trying to find out the arguments of why Java was desinged this way in this question.
The simplest solution for you would be to return the reversed list (which is iterable) instead of a list iterator. Then you can use the shorthand for loop syntax.
A hackish way is outlined in the question mentioned earlier, using an Adapter class that wraps the Iterator as Iterable, and returns the Iterator on the first invocation of iterator(). Look at the adapter code, it's fairly simple. It serves the purpose, but since the iterator can only be used once, it is somewhat an invalid Iterable (it will not be able produce a second iterator).
The key behavior difference shows up when you use it twice:
for(Object a : foo) { }
for(Object a : foo) { }
will process all elements in foo twice if it is a proper Iterable, but only once if it is using the adapter I sketched - the second loop will do nothing.

Categories

Resources