1

I am trying to modify a field in select objects in a List but I am unable to find a way to do so, using plain Iterator because it has no set() method.

I tried using ArrayListIterator that provides a set() method, but this throws a casting exception. Is there way to workaround this?

   Iterator it = topContainer.subList.iterator();
   while (it.hasNext()) {
      MyObject curObj = (MyObject) it.next();
      if ( !curObj.getLabel().contains("/") ) {
           String newLabel = curObj.getLabel() + "/";
           curObj.setLabel(newLabel);
           ((ArrayListIterator) it).set(curObj)
       }
    }

I expect the original current object in the list to be set without incident, but instead I am getting this exception:

java.util.ArrayList$itr cannot be cast to org.apache.commons.collections.iterators.ArrayListIterator

What is the proper way of accomplishing what I would like to do?

Nipuna Priyamal
  • 370
  • 2
  • 14
Introspective
  • 554
  • 2
  • 5
  • 13
  • `curObj.setLabel(newLabel);` should be enough. All you want is change the label on the object, you shouldn't need to overwrite the object with itself in the list – ernest_k Jan 11 '19 at 07:40
  • `MyObject` class have a setter for field Label ? `setLabel` ? – Khalid Shah Jan 11 '19 at 07:40
  • what are you trying to achieve? you can just iterate through the arraylist and modify the object. you do not need to set the object to the iterator – mkjh Jan 11 '19 at 07:40
  • @ernest_k Your suggestion only modifies a copy of the original object fetched from the list via the iterator. I will not modify the original. – Introspective Jan 11 '19 at 07:42
  • @Introspective It does modify the original. `MyObject` is a class right? – Sweeper Jan 11 '19 at 07:44
  • @KhalidShah Yes, MyObject class have a setLabel() setter for the field label. Otherwise the code will not even compile. – Introspective Jan 11 '19 at 07:45
  • @Introspective That's not how it works. Iterators don't provide you with a copy of the object, they provide the object itself. If you edit a property, this will be saved in the original object. – BackSlash Jan 11 '19 at 07:47

3 Answers3

4

You do not need to call set at all. You can just call setLabel on curObj:

// please, don't use raw types!
Iterator<? extends MyObject> it = topContainer.subList.iterator();
while (it.hasNext()) {
   MyObject curObj = it.next();
   if ( !curObj.getLabel().contains("/") ) {
       String newLabel = curObj.getLabel() + "/";
       curObj.setLabel(newLabel);
   }
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • You are correct. I do not need to call `set` at all. Modification works on the original object. I probably missed the `Iterator extends MyObject> it` which resulted in a different exception being thrown and that confused me. Thank you. – Introspective Jan 11 '19 at 08:25
3

The correct way would be following (works not for java versions below 1.5):

for(MyObject curObj : topContainer.subList){
    if (!curObj.getLabel().contains("/")) {
       String newLabel = curObj.getLabel() + "/";
       curObj.setLabel(newLabel);
    }
}

This is an enhanced for-loop, and it does call the iterator too, but you can't see it.

Also setting the object via the iterator is not needed, as you're working with references to Objects in Java, when you edit an object, everyone that has a pointer to that object, will see the change too. For more you can read this great post: Is Java “pass-by-reference” or “pass-by-value”?

If you can't use Java 5, then you're missing out big time. The current java version is 11. So you should really, really, really, upgrade your JDK

Lino
  • 19,604
  • 6
  • 47
  • 65
2

you just have to set the label. In JAVA 11 you can use streams. it makes your code more readable.

List<MyObject> list = topContainer.subList;
list
    .stream()
    .filter(Predicate.not(e->e.getLabel().contains("/")))
    .forEach(e->e.setLabel(e.getLabel()+"/"));

In java 8 you can use

(!e->e.getLabel().contains("/"))

instead of

Predicate.not(e->e.getLabel().contains("/")

Khalid Shah
  • 3,132
  • 3
  • 20
  • 39