Jim
Jim

Reputation: 4405

Could we remove while iterating if we just remove 1 element?

I have a list of custom objects. I need to get/remove a specific object from that list but the equals implemented would not work based on what I need to search.
The following would work:

int index = -1;  
for(int i = 0; i < list.size(); i++) {
  if(list.get(i).getAttr().equals(arg)) {
     index = i;  
     break;  
  }  
}    
CustomObject = list.remove(index);  
// use CustomObject here  

I was wondering if I could do the list.remove inside the for loop despite not using an iterator since the loop breaks immediately

Upvotes: 1

Views: 138

Answers (3)

Holger
Holger

Reputation: 298153

There is no special program state associated with “being inside a for loop”. What matters, are the actions your program performs.

So

int index = -1;
for(int i = 0; i < list.size(); i++) {
    if(list.get(i).getAttr().equals(arg)) {
        index = i;
        break;
    }
}
CustomObject o = list.remove(index);
// use CustomObject here

is identical to

for(int i = 0; i < list.size(); i++) {
    if(list.get(i).getAttr().equals(arg)) {
        CustomObject o = list.remove(i);
        // use CustomObject here
        break;
    }
}

as it performs the same actions (letting aside that the first variant will throw when no match has been found). The differences regarding local variables defined in these code snippets are, well, local and do not affect anything outside the containing method.

That said, the rule that you must not modify a collection (except through the iterator) while iterating over it, applies to iterator-based loops, where you are not in control of the iterator’s internal state. When you are using an index based loop and fully understand the implications of removing an object at a particular index (of a random access list), you can even continue iterating. The important aspects, to do it correctly, are that the indices of all subsequent elements decrease by one when removing an element, further the size decreases so you must either, reread the size or decrement a previously cached size value.

E.g., the following loop is valid

for(int i = 0; i < list.size(); i++) {// rereads size on each iteration
    if(list.get(i).getAttr().equals(arg)) {
        CustomObject o = list.remove(i--); // decrease index after removal
        // use CustomObject here
        // continue
    }
}

But, of course, it’s more idiomatic to use an Iterator or removeIf, as these approaches are not only easier to handle, they also work with other collections than random access lists. And especially removeIf may be more efficient when you remove more than one element.

Upvotes: 2

Sabareesh Muralidharan
Sabareesh Muralidharan

Reputation: 647

Just another way using streams,

    List<String> str1 = new ArrayList<String>();
    str1.add("A");
    str1.add("B");
    str1.add("D");
    str1.add("D");

    Optional<Object> foundVal = str1.stream().filter(s -> 
            s.contains("D")).findFirst().map(val -> {
                                             str1.remove(val);
                                             return val;
                                             });


    System.out.println(str1);
    System.out.print(" " + foundVal.get());

Output

[A, B, D]  D

Upvotes: 0

Olivier Gr&#233;goire
Olivier Gr&#233;goire

Reputation: 35427

Using the delete(int) method in your loop will work just fine.

Your loop is closed so you have full control on i and you can use the list as you please. You don't use i after having deleted the first element that matches, so there are no caveat. If you were to reuse it, you would have to not increment it.

To avoid any trouble, the following if both more readable and expressive. Also, it's totally implementation-agnostic.

CustomObject deletedObject = null;
for (Iterator<CustomObject> i = list.iterator(); i.hasNext(); ) {
  CustomObject candidate = i.next();
  if (candidate.getAttr().equals(arg)) {
    deletedObject = candidate;
    i.remove();
    break;
  }
}
if (deletedObject != null) {
  // Do something with deletedObject
}

Upvotes: 2

Related Questions