2

I have a String List.On a satisfied Condition ,I need to group strings and remove those before iterating. For example;

List<String> test = new ArrayList();
List<String> newLst = new ArrayList();
test.add("A1");
test.add("A2");
test.add("A3");
test.add("A1B1");
test.add("C1");
for(String s: test){
    if(s.startsWith("A"){
        newLst.add(s);
        test.remove(s);
    }
}

Once A1 reaches the loop,collect related string in new list and remove it from existing.

Getting Concurrent Modification exception.Kindly help to solve this.

Output: newLst: A1,A2,A3 test : A1B1,C1

newLst : A1B1 test:C1

newLst : C1

Jayanthi
  • 41
  • 2
  • 3
    Does this answer your question? [Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop](https://stackoverflow.com/questions/223918/iterating-through-a-collection-avoiding-concurrentmodificationexception-when-re) – jhamon Feb 26 '20 at 09:42
  • 1
    `test.removeIf(s -> s.startsWith("A") && newLst.add(s));` – Holger Feb 26 '20 at 10:29

3 Answers3

1

You could use an explicit Iterator to iterate over the List, and use that Iterator's remove() method inside the loop (instead of List's remove()), but it would be simpler to remove from test all the elements added to newLst after the loop:

for(String s: test){
    if(s.startsWith("A"){
        newLst.add(s);
    }
}
test.removeAll(newLst);
Eran
  • 387,369
  • 54
  • 702
  • 768
  • 2
    Using an `Iterator` to remove the matches yields quadratic time complexity due to the linear complexity of `ArrayList`’s remove operation. Using `removeAll` avoids that for the removal but brings in a similar time complexity due to the hidden dependency to `contains` on `newList`. A short solution avoiding both, is `test.removeIf(s -> s.startsWith("A") && newLst.add(s));`. – Holger Feb 26 '20 at 10:46
1

You can filter out elements starting with A using stream:

List<String> result = test.stream()
            .filter(line -> line.startsWith("A")) 
            .collect(Collectors.toList()); 
result.forEach(System.out::println);  //This is for printing elements
Miss Chanandler Bong
  • 4,081
  • 10
  • 26
  • 36
Eshu
  • 499
  • 4
  • 15
1

Why you are getting ConcurrentModificationException ?

That's because you are trying to modify the collection while iterating over it's items. The only safe way to modify your collection during iteration Iterator.remove(); The same applies for Iterator.add() (Whether you delete or add an item it counts as a modification).

JDK < 8 SOLUTION

List<String> sourceList = new ArrayList();
List<String> destList = new ArrayList();
sourceList.add("A1");
sourceList.add("A2");
sourceList.add("A3");
sourceList.add("A1B1");
sourceList.add("C1");
Iterator<String> iterator = sourceList.iterator();

while (iterator.hasNext()) {
    String s = iterator.next();
    if(s.startsWith("A"){
        destList.add(s);
        iterator.remove(s);
    }
}

JDK > 8 SOLUTION

List<String> destList = sourceList.stream()
      .filter(item -> item.startsWith("A")) 
      .collect(Collectors.toList());

Note that Java streams use Spliterator which quite different than an Iterator.

A stream source is described by an abstraction called Spliterator. As its name suggests, Spliterator combines two behaviors: accessing the elements of the source (iterating), and possibly decomposing the input source for parallel execution (splitting).

For further details , i advise you to check this interesting post about how streams works under the hood

Hassam Abdelillah
  • 2,246
  • 3
  • 16
  • 37