In your case, there's no need to iterate through the list, because you know which object to delete. You have several options. First you can remove the object by index (so if you know, that the object is the second list element):
a.remove(1); // indexes are zero-based
Or, you can remove the first occurence of your string:
a.remove("acbd"); // removes the first String object that is equal to the
// String represented by this literal
Or, remove all strings with a certain value:
while(a.remove("acbd")) {}
It's a bit more complicated, if you have more complex objects in your collection and want to remove instances, that have a certain property. So that you can't remove them by using remove with an object that is equal to the one you want to delete.
In those case, I usually use a second list to collect all instances that I want to delete and remove them in a second pass:
List<MyBean> deleteCandidates = new ArrayList<>();
List<MyBean> myBeans = getThemFromSomewhere();
// Pass 1 - collect delete candidates
for (MyBean myBean : myBeans) {
if (shallBeDeleted(myBean)) {
deleteCandidates.add(myBean);
}
}
// Pass 2 - delete
for (MyBean deleteCandidate : deleteCandidates) {
myBeans.remove(deleteCandidate);
}
Answer from Andreas Dolk on Stack OverflowQuestion and solution: How to delete or add an object to/from array list while iterating it.
Java how to remove element from List efficiently - Stack Overflow
java - Remove objects from an ArrayList based on a given criteria - Stack Overflow
A problem with java arraylist remove method
Videos
In your case, there's no need to iterate through the list, because you know which object to delete. You have several options. First you can remove the object by index (so if you know, that the object is the second list element):
a.remove(1); // indexes are zero-based
Or, you can remove the first occurence of your string:
a.remove("acbd"); // removes the first String object that is equal to the
// String represented by this literal
Or, remove all strings with a certain value:
while(a.remove("acbd")) {}
It's a bit more complicated, if you have more complex objects in your collection and want to remove instances, that have a certain property. So that you can't remove them by using remove with an object that is equal to the one you want to delete.
In those case, I usually use a second list to collect all instances that I want to delete and remove them in a second pass:
List<MyBean> deleteCandidates = new ArrayList<>();
List<MyBean> myBeans = getThemFromSomewhere();
// Pass 1 - collect delete candidates
for (MyBean myBean : myBeans) {
if (shallBeDeleted(myBean)) {
deleteCandidates.add(myBean);
}
}
// Pass 2 - delete
for (MyBean deleteCandidate : deleteCandidates) {
myBeans.remove(deleteCandidate);
}
One-liner (java8):
list.removeIf(s -> s.equals("acbd")); // removes all instances, not just the 1st one
(does all the iterating implicitly)
Use an Iterator instead and use Iterator#remove method:
for (Iterator<String> it = a.iterator(); it.hasNext(); ) {
String str = it.next();
if (!str.equals("foo") || !str.equals("bar")) {
it.remove();
}
}
From your question:
messing with for iterators is not really good practice
In fact, if you code oriented to interfaces and use List instead of ArrayList directly, using get method could become into navigating through all the collection to get the desired element (for example, if you have a List backed by a single linked list). So, the best practice here would be using iterators instead of using get.
what is the best practice to remove items from a list efficiently?
Not only for Lists, but for any Collection that supports Iterable, and assuming you don't have an index or some sort of key (like in a Map) to directly access to an element, the best way to remove an element would be using Iterator#remove.
You have three main choices:
Use an
Iterator, since it has that handyremovemethod on it. :-)Iterator<String> it = list.iterator(); while (it.hasNext()) { if (/*...you want to remove `it.next()`...*/) { it.remove(); } }Loop backward through the list, so that if you remove something, it doesn't matter for the next iteration. This also has the advantage of only calling
list.size()once.for (int index = list.size() - 1; index >= 0; --index) { // ...check and optionally remove here... }Use a
whileloop instead, and only increment the index variable if you don't remove the item.int index = 0; while (index < list.size()) { if (/*...you want to remove the item...*/) { list.removeAt(index); } else { // Not removing, move to the next ++index; } }
Remember that unless you know you're dealing with an ArrayList, the cost of List#get(int) may be high (it may be a traversal). But if you know you're dealing with ArrayList (or similar), then...
You can use Collection::removeIf(Predicate filter) (available from Java8 onwards), here is a simple example:
final Collection<Integer> list = new ArrayList<>(Arrays.asList(1, 2));
list.removeIf(value -> value < 2);
System.out.println(list); // outputs "[2]"
You must use an Iterator to iterate and the remove function of the iterator (not of the list) :
Iterator<Pulse> iter = pulseArray.iterator();
while (iter.hasNext()) {
Pulse p = iter.next();
if (p.getCurrent()==null) iter.remove();
}
Note that the Iterator#remove function is said to be optionnal but it is implemented by the ArrayList's iterator.
Here's the code of this concrete function from ArrayList.java :
765 public void remove() {
766 if (lastRet < 0)
767 throw new IllegalStateException();
768 checkForComodification();
769
770 try {
771 ArrayList.this.remove(lastRet);
772 cursor = lastRet;
773 lastRet = -1;
774 expectedModCount = modCount;
775 } catch (IndexOutOfBoundsException ex) {
776 throw new ConcurrentModificationException();
777 }
778 }
779
780 final void checkForComodification() {
781 if (modCount != expectedModCount)
782 throw new ConcurrentModificationException();
783 }
784 }
The expectedModCount = modCount; line is why it won't throw an exception when you use it while iterating.