We all know you can't do the following because of ConcurrentModificationException:
for (Object i : l) {
if (condition(i)) {
l.remove(i);
}
}
But this apparently works sometimes, but not always. Here's some specific code:
public static void main(String[] args) {
Collection<Integer> l = new ArrayList<>();
for (int i = 0; i < 10; ++i) {
l.add(4);
l.add(5);
l.add(6);
}
for (int i : l) {
if (i == 5) {
l.remove(i);
}
}
System.out.println(l);
}
This, of course, results in:
Exception in thread "main" java.util.ConcurrentModificationException
Even though multiple threads aren't doing it. Anyway.
What's the best solution to this problem? How can I remove an item from the collection in a loop without throwing this exception?
I'm also using an arbitrary Collection here, not necessarily an ArrayList, so you can't rely on get.
Iterator.remove() is safe, you can use it like this:
List<String> list = new ArrayList<>();
// This is a clever way to create the iterator and call iterator.hasNext() like
// you would do in a while-loop. It would be the same as doing:
// Iterator<String> iterator = list.iterator();
// while (iterator.hasNext()) {
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String string = iterator.next();
if (string.isEmpty()) {
// Remove the current element from the iterator and the list.
iterator.remove();
}
}
Note that Iterator.remove() is the only safe way to modify a collection during iteration; the behavior is unspecified if the underlying collection is modified in any other way while the iteration is in progress.
Source: docs.oracle > The Collection Interface
And similarly, if you have a ListIterator and want to add items, you can use ListIterator#add, for the same reason you can use Iterator#remove — it's designed to allow it.
In your case you tried to remove from a list, but the same restriction applies if trying to put into a Map while iterating its content.
This works:
Iterator<Integer> iter = l.iterator();
while (iter.hasNext()) {
if (iter.next() == 5) {
iter.remove();
}
}
I assumed that since a foreach loop is syntactic sugar for iterating, using an iterator wouldn't help... but it gives you this .remove() functionality.
With Java 8 you can use the new removeIf method. Applied to your example:
Collection<Integer> coll = new ArrayList<>();
//populate
coll.removeIf(i -> i == 5);
A simple test as example:
#Test
public void testRemoveIfOneList() {
List<String> outer = new ArrayList<>();
outer.add("one");
outer.add("two");
outer.add("three");
outer.removeIf(o -> o.length() == 3);
assertEquals(1, outer.size());
}
It even works when you compare two lists and want to remove from both.
#Test
public void testRemoveIfTwoLists() {
List<String> outer = new ArrayList<>();
outer.add("one");
outer.add("two");
outer.add("three");
List<String> inner = new ArrayList<>();
inner.addAll(outer);
// first, it removes from inner, and if anything is removed, then removeIf() returns true,
// leading to removing from outer
outer.removeIf(o -> inner.removeIf(i -> i.equals(o)));
assertEquals(0, outer.size());
assertEquals(0, inner.size());
}
However, if one of the list has duplicates, make sure it's iterated in the inner loop, because for inner list, it will remove all elements meeting the criteria, but for outer list, when any element is removed, it will return immediately and stops checking.
This test will fail:
#Test
public void testRemoveIfTwoListsInnerHasDuplicates() {
List<String> outer = new ArrayList<>();
outer.add("one");
outer.add("one");
outer.add("two");
outer.add("two");
outer.add("three");
outer.add("three");
List<String> inner = new ArrayList<>();
inner.addAll(outer); // both have duplicates
// remove all elements from inner(executed twice), then remove from outer
// but only once! if anything is removed, it will return immediately!!
outer.removeIf(o -> inner.removeIf(i -> i.equals(o)));
assertEquals(0, inner.size()); // pass, inner all removed
assertEquals(0, outer.size()); // will fail, outer has size = 3
}
Since the question has been already answered i.e. the best way is to use the remove method of the iterator object, I would go into the specifics of the place where the error "java.util.ConcurrentModificationException" is thrown.
Every collection class has a private class which implements the Iterator interface and provides methods like next(), remove() and hasNext().
The code for next looks something like this...
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
Here the method checkForComodification is implemented as
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
So, as you can see, if you explicitly try to remove an element from the collection. It results in modCount getting different from expectedModCount, resulting in the exception ConcurrentModificationException.
You can either use the iterator directly like you mentioned, or else keep a second collection and add each item you want to remove to the new collection, then removeAll at the end. This allows you to keep using the type-safety of the for-each loop at the cost of increased memory use and cpu time (shouldn't be a huge problem unless you have really, really big lists or a really old computer)
public static void main(String[] args)
{
Collection<Integer> l = new ArrayList<Integer>();
Collection<Integer> itemsToRemove = new ArrayList<>();
for (int i=0; i < 10; i++) {
l.add(Integer.of(4));
l.add(Integer.of(5));
l.add(Integer.of(6));
}
for (Integer i : l)
{
if (i.intValue() == 5) {
itemsToRemove.add(i);
}
}
l.removeAll(itemsToRemove);
System.out.println(l);
}
In such cases a common trick is (was?) to go backwards:
for(int i = l.size() - 1; i >= 0; i --) {
if (l.get(i) == 5) {
l.remove(i);
}
}
That said, I'm more than happy that you have better ways in Java 8, e.g. removeIf or filter on streams.
Same answer as Claudius with a for loop:
for (Iterator<Object> it = objects.iterator(); it.hasNext();) {
Object object = it.next();
if (test) {
it.remove();
}
}
With Eclipse Collections, the method removeIf defined on MutableCollection will work:
MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.lessThan(3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);
With Java 8 Lambda syntax this can be written as follows:
MutableList<Integer> list = Lists.mutable.of(1, 2, 3, 4, 5);
list.removeIf(Predicates.cast(integer -> integer < 3));
Assert.assertEquals(Lists.mutable.of(3, 4, 5), list);
The call to Predicates.cast() is necessary here because a default removeIf method was added on the java.util.Collection interface in Java 8.
Note: I am a committer for Eclipse Collections.
Make a copy of existing list and iterate over new copy.
for (String str : new ArrayList<String>(listOfStr))
{
listOfStr.remove(/* object reference or index */);
}
People are asserting one can't remove from a Collection being iterated by a foreach loop. I just wanted to point out that is technically incorrect and describe exactly (I know the OP's question is so advanced as to obviate knowing this) the code behind that assumption:
for (TouchableObj obj : untouchedSet) { // <--- This is where ConcurrentModificationException strikes
if (obj.isTouched()) {
untouchedSet.remove(obj);
touchedSt.add(obj);
break; // this is key to avoiding returning to the foreach
}
}
It isn't that you can't remove from the iterated Colletion rather that you can't then continue iteration once you do. Hence the break in the code above.
Apologies if this answer is a somewhat specialist use-case and more suited to the original thread I arrived here from, that one is marked as a duplicate (despite this thread appearing more nuanced) of this and locked.
With a traditional for loop
ArrayList<String> myArray = new ArrayList<>();
for (int i = 0; i < myArray.size(); ) {
String text = myArray.get(i);
if (someCondition(text))
myArray.remove(i);
else
i++;
}
ConcurrentHashMap or ConcurrentLinkedQueue or ConcurrentSkipListMap may be another option, because they will never throw any ConcurrentModificationException, even if you remove or add item.
Another way is to use a copy of your arrayList just for iteration:
List<Object> l = ...
List<Object> iterationList = ImmutableList.copyOf(l);
for (Object curr : iterationList) {
if (condition(curr)) {
l.remove(curr);
}
}
A ListIterator allows you to add or remove items in the list. Suppose you have a list of Car objects:
List<Car> cars = ArrayList<>();
// add cars here...
for (ListIterator<Car> carIterator = cars.listIterator(); carIterator.hasNext(); )
{
if (<some-condition>)
{
carIterator().remove()
}
else if (<some-other-condition>)
{
carIterator().add(aNewCar);
}
}
Now, You can remove with the following code
l.removeIf(current -> current == 5);
I know this question is too old to be about Java 8, but for those using Java 8 you can easily use removeIf():
Collection<Integer> l = new ArrayList<Integer>();
for (int i=0; i < 10; ++i) {
l.add(new Integer(4));
l.add(new Integer(5));
l.add(new Integer(6));
}
l.removeIf(i -> i.intValue() == 5);
Java Concurrent Modification Exception
Single thread
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String value = iter.next()
if (value == "A") {
list.remove(it.next()); //throws ConcurrentModificationException
}
}
Solution: iterator remove() method
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String value = iter.next()
if (value == "A") {
it.remove()
}
}
Multi thread
copy/convert and iterate over another one collection. For small collections
synchronize[About]
thread safe collection[About]
I have a suggestion for the problem above. No need of secondary list or any extra time. Please find an example which would do the same stuff but in a different way.
//"list" is ArrayList<Object>
//"state" is some boolean variable, which when set to true, Object will be removed from the list
int index = 0;
while(index < list.size()) {
Object r = list.get(index);
if( state ) {
list.remove(index);
index = 0;
continue;
}
index += 1;
}
This would avoid the Concurrency Exception.
for (Integer i : l)
{
if (i.intValue() == 5){
itemsToRemove.add(i);
break;
}
}
The catch is the after removing the element from the list if you skip the internal iterator.next() call. it still works! Though I dont propose to write code like this it helps to understand the concept behind it :-)
Cheers!
Example of thread safe collection modification:
public class Example {
private final List<String> queue = Collections.synchronizedList(new ArrayList<String>());
public void removeFromQueue() {
synchronized (queue) {
Iterator<String> iterator = queue.iterator();
String string = iterator.next();
if (string.isEmpty()) {
iterator.remove();
}
}
}
}
I know this question assumes just a Collection, and not more specifically any List. But for those reading this question who are indeed working with a List reference, you can avoid ConcurrentModificationException with a while-loop (while modifying within it) instead if you want to avoid Iterator (either if you want to avoid it in general, or avoid it specifically to achieve a looping order different from start-to-end stopping at each element [which I believe is the only order Iterator itself can do]):
*Update: See comments below that clarify the analogous is also achievable with the traditional-for-loop.
final List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; ++i){
list.add(i);
}
int i = 1;
while(i < list.size()){
if(list.get(i) % 2 == 0){
list.remove(i++);
} else {
i += 2;
}
}
No ConcurrentModificationException from that code.
There we see looping not start at the beginning, and not stop at every element (which I believe Iterator itself can't do).
FWIW we also see get being called on list, which could not be done if its reference was just Collection (instead of the more specific List-type of Collection) - List interface includes get, but Collection interface does not. If not for that difference, then the list reference could instead be a Collection [and therefore technically this Answer would then be a direct Answer, instead of a tangential Answer].
FWIWW same code still works after modified to start at beginning at stop at every element (just like Iterator order):
final List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; ++i){
list.add(i);
}
int i = 0;
while(i < list.size()){
if(list.get(i) % 2 == 0){
list.remove(i);
} else {
++i;
}
}
One solution could be to rotate the list and remove the first element to avoid the ConcurrentModificationException or IndexOutOfBoundsException
int n = list.size();
for(int j=0;j<n;j++){
//you can also put a condition before remove
list.remove(0);
Collections.rotate(list, 1);
}
Collections.rotate(list, -1);
Try this one (removes all elements in the list that equal i):
for (Object i : l) {
if (condition(i)) {
l = (l.stream().filter((a) -> a != i)).collect(Collectors.toList());
}
}
You can use a while loop.
Iterator<Map.Entry<String, String>> iterator = map.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry<String, String> entry = iterator.next();
if(entry.getKey().equals("test")) {
iterator.remove();
}
}
I ended up with this ConcurrentModificationException, while iterating the list using stream().map() method. However the for(:) did not throw the exception while iterating and modifying the the list.
Here is code snippet , if its of help to anyone:
here I'm iterating on a ArrayList<BuildEntity> , and modifying it using the list.remove(obj)
for(BuildEntity build : uniqueBuildEntities){
if(build!=null){
if(isBuildCrashedWithErrors(build)){
log.info("The following build crashed with errors , will not be persisted -> \n{}"
,build.getBuildUrl());
uniqueBuildEntities.remove(build);
if (uniqueBuildEntities.isEmpty()) return EMPTY_LIST;
}
}
}
if(uniqueBuildEntities.size()>0) {
dbEntries.addAll(uniqueBuildEntities);
}
If using HashMap, in newer versions of Java (8+) you can select each of 3 options:
public class UserProfileEntity {
private String Code;
private String mobileNumber;
private LocalDateTime inputDT;
// getters and setters here
}
HashMap<String, UserProfileEntity> upMap = new HashMap<>();
// remove by value
upMap.values().removeIf(value -> !value.getCode().contains("0005"));
// remove by key
upMap.keySet().removeIf(key -> key.contentEquals("testUser"));
// remove by entry / key + value
upMap.entrySet().removeIf(entry -> (entry.getKey().endsWith("admin") || entry.getValue().getInputDT().isBefore(LocalDateTime.now().minusMinutes(3)));
The best way (recommended) is use of java.util.concurrent package. By
using this package you can easily avoid this exception. Refer
Modified Code:
public static void main(String[] args) {
Collection<Integer> l = new CopyOnWriteArrayList<Integer>();
for (int i=0; i < 10; ++i) {
l.add(new Integer(4));
l.add(new Integer(5));
l.add(new Integer(6));
}
for (Integer i : l) {
if (i.intValue() == 5) {
l.remove(i);
}
}
System.out.println(l);
}
Iterators are not always helpful when another thread also modifies the collection. I had tried many ways but then realized traversing the collection manually is much safer (backward for removal):
for (i in myList.size-1 downTo 0) {
myList.getOrNull(i)?.also {
if (it == 5)
myList.remove(it)
}
}
In case ArrayList:remove(int index)- if(index is last element's position) it avoids without System.arraycopy() and takes not time for this.
arraycopy time increases if(index decreases), by the way elements of list also decreases!
the best effective remove way is- removing its elements in descending order:
while(list.size()>0)list.remove(list.size()-1);//takes O(1)
while(list.size()>0)list.remove(0);//takes O(factorial(n))
//region prepare data
ArrayList<Integer> ints = new ArrayList<Integer>();
ArrayList<Integer> toRemove = new ArrayList<Integer>();
Random rdm = new Random();
long millis;
for (int i = 0; i < 100000; i++) {
Integer integer = rdm.nextInt();
ints.add(integer);
}
ArrayList<Integer> intsForIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsDescIndex = new ArrayList<Integer>(ints);
ArrayList<Integer> intsIterator = new ArrayList<Integer>(ints);
//endregion
// region for index
millis = System.currentTimeMillis();
for (int i = 0; i < intsForIndex.size(); i++)
if (intsForIndex.get(i) % 2 == 0) intsForIndex.remove(i--);
System.out.println(System.currentTimeMillis() - millis);
// endregion
// region for index desc
millis = System.currentTimeMillis();
for (int i = intsDescIndex.size() - 1; i >= 0; i--)
if (intsDescIndex.get(i) % 2 == 0) intsDescIndex.remove(i);
System.out.println(System.currentTimeMillis() - millis);
//endregion
// region iterator
millis = System.currentTimeMillis();
for (Iterator<Integer> iterator = intsIterator.iterator(); iterator.hasNext(); )
if (iterator.next() % 2 == 0) iterator.remove();
System.out.println(System.currentTimeMillis() - millis);
//endregion
for index loop: 1090 msec
for desc index: 519 msec---the best
for iterator: 1043 msec
you can also use Recursion
Recursion in java is a process in which a method calls itself continuously. A method in java that calls itself is called recursive method.
This is a follow up to my previous question :
Collection - Iterator.remove() vs Collection.remove()
The below two pieces of code , which apparently differs only by a single line , but one throws exception and other don't . Can you please explain the difference ?
List<String> list = new ArrayList<String>
(Arrays.asList("noob1","noob2","noob3"));
System.out.println(list);
for (String str : list) {
if (str.equals("noob2")) {
list.remove(str);
}
}
runs fine , but if i change the condition to
if (!str.equals("noob2"))
the code throws exception !
What happens in this situation is you are removing the second list element.
List<String> list = new ArrayList<String>
(Arrays.asList("noob1", "noob2", "noob3", "noob4"));
System.out.println(list);
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
String str = iterator.next();
if (str.equals("noob3")) {
System.out.println("Checking "+str);
list.remove(str);
}
}
System.out.println(list);
prints
[noob1, noob2, noob3, noob4]
Checking noob1
Checking noob2
Checking noob3
[noob1, noob2, noob4]
By removing the second last element you have reduced the size to the number of elements which you have iterated over.
// from ArrayList.Itr
public boolean hasNext() {
return cursor != size;
}
This causes the loop to exit early before the concurrent modifcation check is performed in next(). If you remove any other element next() is called and you get a CME.
BTW Something which also bypasses the check is
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
String str = iterator.next();
System.out.println("Checking "+str);
if (str.equals("noob2")) {
list.remove("noob1");
list.remove("noob3");
}
}
as long as the size of the collection is the same as the index it is up to, the check is not performed.
The for loop is just a simplified syntax for an iterator scan of the list. The iterator may throw an exception if the list is modified under it, but it is not guaranteed. Because of hasNext, iterators are often working one element ahead, making the first case less likely to be affected by list modification. By the time "noob2" is removed, the iterator already knows about "noob3".
Actually you should never remove collections' elements during "casual" iterating. When you have to modify your collection in some loop you have to use iterator to make these operations.
public class Test {
public static void main(String... args) {
List<String> list = new ArrayList<String>(Arrays.asList("noob1", "noob2", "noob3"));
System.out.println(list);
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String str = iterator.next();
if (!str.equals("noob2")) {
iterator.remove();
}
}
System.out.println(list);
}
}
I suppose the exception is thown because you are trying to change a collection you are looping on... and not because the if condition.
I suggest you to create a new list only containing the items that verify the condition. Add them to the new list and avoid to change the original collection.
It's because you are trying to remove from a Collection you are currently iterating through. Making a minor alteration you can do what you want to do:
String[] strValues = {"noob1","noob2","noob3"}; // <<< Array
List<String> list = new ArrayList<String>(Arrays.asList(strValues));
System.out.println(list);
for (String str : strValues) { // << List is duplicate of array so can iterate through array
if (!str.equals("noob2")) {
list.remove(str);
}
}
That should work. Hopefully
Well, your first case doesn't throw the Exception because, the iterator returns false for Iterator.hasNext() at index 2 as you remove the element at index 1.
Iterator<String> itr = list.iterator();
while(itr.hasNext()){
String s= itr.next();
if(s.equals("noob2")){
list.remove(s); // size of the list is 2 here
System.out.println(itr.hasNext());// this returns false as it doesn't have anything at index 2 now.(on 2nd iteration )
}
}
You can test it clearly using a simple for-loop:
for (int i=0; i<list.size(); i++) {
if (list.get(i).equals("noob2")) {
System.out.println(list.get(i));
System.out.println(list.size());
list.remove(list.get(i));
System.out.println(list.size());
}
}
Output:
[noob1, noob2, noob3]
noob2
3
2
Notice the size of the list after you remove the element, which fails after incrementing. 2<2 which is false
I have a generic arraylist of an object here I want to remove certain elements, The problem is when I iterate the list with for loop, I can't do a simple sequence of remove()'s because the elements are shifted after each removal.
Thanks
Use Iterator to remove element
Like
Iterator itr = list.iterator();
String strElement = "";
while (itr.hasNext()) {
strElement = (String) itr.next();
if (strElement.equals("2")) {
itr.remove();
}
}
See here
You can iterate the list this way ...
public void clean(List<Kopek> kopeks) {
for(Kopek kopek : kopeks) {
if (kopek.isDirty())
kopeks.remove(kopek);
}
}
Which is equiv to ...
public void clean1(List<Kopek> kopeks) {
Iterator<Kopek> kopekIter = kopeks.iterator();
while (kopekIter.hasNext()) {
Kopek kopek = kopekIter.next();
if (kopek.isDirty())
kopeks.remove(kopek);
}
}
Don't do this ... (due to the reason you have already observed.)
public void clean(List<Kopek> kopeks) {
for(int i=0; i<kopeks.size(); i++) {
Kopek kopek = kopeks.get(i);
if (kopek.isDirty())
kopeks.remove(i);
}
}
However, I believe removal by index rather than by object is more efficient. Removal by object is not efficient because the list is in most cases not a hashed list.
kopeks.remove(kopek);
vs
kopeks.remove(i);
To achieve positional remove, by treating a moving target appropriately ...
public void clean(List<Kopek> kopeks) {
int i=0;
while(i<kopeks.size()) {
Kopek kopek = kopeks.get(i);
if (kopek.isDirty()) // no need to increment.
kopeks.remove(i);
else
i++;
}
}
If you have the objects that you want to remove from your ArrayList<T> you can use :
mArrayList.remove(object);
or you can use an Iterator to remove your objects:
while(iterator.hasNext()){
if(iterator.next() == some condition for removal){
iterator.remove();
}
}
You could iterate backwards and remove as you go through the ArrayList. This has the advantage of subsequent elements not needing to shift and is easier to program than moving forwards.
List<String> arr = new ArrayList<String>();
ListIterator<String> li = arr.listIterator(arr.size());
// Iterate in reverse.
while(li.hasPrevious()) {
String str=li.previous();
if(str.equals("A"))
{
li.remove();
}
}
Create a separate ArrayList of Index of the data to be removed from the original ArrayList, then remove those elements by looping over it with for loop.
ArrayList<Myobj> arr = new ArrayList<Myobj>();
for (Myobj o : arr){
arr.remove(arr.indexOf(o));
}
without using iterators also solves the issue.. All i wanted to do is get the index which are to be deleted and sort it in decending order then remove it from the list.
check the code below
Arraylist<obj> addlist = getlist();
List<Integer> indices = new ArrayList<Integer>();
for(int i=0; i<addlist.size() ;i++){
if(addlist.get(i).getDelete()){
indices.add(i);
}
}
Collections.sort(indices, Collections.reverseOrder());
for (int i : indices)
addlist.remove(i);
I'm trying to remove a particular element from Arraylist, it throws an ConcurrentModificationException
ArrayList<String> ar = new ArrayList<String>();
ar.add("a");
ar.add("b");
ar.add("c");
ar.add("a");
ar.add("e");
for(String st: ar){
System.out.println("st="+st);
if(st.equals("a")){
ar.remove(st);
}
}
any comments, what am I doing wrong?
Only remove an element from the array while iterating by using Iterator.remove().
The line for(String st: ar) { is a bit misleading. You're actually creating an iterator behind the scenes which is being used for this iteration. If you need to remove elements from within the iteration, you need to explicitly use an iterator so that you can call iterator.remove().
ArrayList<String> ar = new ArrayList<String>();
ar.add("a");
ar.add("b");
ar.add("c");
ar.add("a");
ar.add("e");
Iterator<String> it = ar.iterator();
while (it.hasNext()) {
String st = it.next();
System.out.println("st="+st);
if (st.equals("a")) {
it.remove();
}
}
you are modifing the array you are iterating on.
I suggest you to use the Iterator to do similar things.
You're removing an element from a collection while you're iterating over that collection, without using the iterator to do it. Don't do that. There are lots of alternatives, primarily:
Use indexes instead (get, remove(int)) being careful about your counts so that you don't skip over items
for (int i = 0; i < ar.size(); i++) {
String st = ar.get(i);
System.out.println("st="+st);
if(st.equals("a")) {
ar.remove(i);
i--; // We want to use this index again
}
}
Build up a collection of items to remove, then remove them all afterwards
List<String> elementsToRemove = new ArrayList<String>();
for(String st: ar){
System.out.println("st="+st);
if(st.equals("a")){
elementsToRemove.add(st);
}
}
ar.removeAll(elementsToRemove);
Remove using the iterator, if the iterator supports removal (as ArrayList's does)
for (Iterator<String> it = ar.iterator(); it.hasNext(); ) {
String st = it.next();
System.out.println("st="+st);
if(st.equals("a")) {
it.remove();
}
}
program:
public class SortedSet1 {
public static void main(String[] args) {
List ac= new ArrayList();
c.add(ac);
ac.add(0,"hai");
ac.add(1,"hw");
ac.add(2,"ai");
ac.add(3,"hi");
ac.add("hai");
Collections.sort(ac);
Iterator it=ac.iterator();
k=0;
while(it.hasNext()) {
System.out.println(""+ac.get(k));
k++;
}
}
}
output:
ai
hai
hi
hw
hai
how it execute 5 times??
while come to hai no next element present so condition false. But how it executed.
Your loop above iterates through the list using an index. it.hasNext() returns true until it reaches the end of the list. Since you don't call it.next() within your loop to advance the iterator, it.hasNext() keeps returning true, and your loop rolls on. Until, that is, k gets to be 5, at which point an IndexOutOfBoundsException is thrown, which exits the loop.
The proper idiom using an iterator would be
while(it.hasNext()){
System.out.println(it.next());
}
or using an index
for(int k=0; k<ac.size(); k++) {
System.out.println(ac.get(k));
}
However since Java5, the preferred way is using the foreach loop (and generics):
List<String> ac= new ArrayList<String>();
...
for(String elem : ac){
System.out.println(elem);
}
the point is ac.get(k) doesn't consume any element of the iterator at the contrary of it.next()
That loop will never terminate. it.hasNext does not advance the iterator. You have to call it.next() to advance it. The loop probably terminates because k becomes 5 at which point the Arraylist with throw a bounds exception.
The correct form of iterating a list (containing strings) is either:
Iterator it = ac.iterator();
while (it.hasNext) {
System.out.println((String) it.next());
}
Or if the list is typed, e.g. ArrayList
for (String s : ac) {
System.out.println((String) s);
}
Or if you absolutely know this is an array list and need speed over terseness:
for (int i = 0; i < ac.size(); i++) {
System.out.println(ac.get(i));
}