This question already has answers here:
How can I iterate over an object while modifying it in Java? [duplicate]
(6 answers)
Why isn't this code causing a ConcurrentModificationException? [duplicate]
(4 answers)
Why is a ConcurrentModificationException thrown and how to debug it
(8 answers)
Closed 10 years ago.
when remove the second last element there is no ConcurrentModificationException
List<String> myList1 = new ArrayList<String>();
Collections.addAll(myList1, "str1","str2","str3","str4","str5");
for(String element : myList1){//no ConcurrentModificationException here
if(element.equalsIgnoreCase("str4"))
myList1.remove("str4");
}
System.out.println(myList1);
But when remove other elements there is a ConcurrentModificationException
List<String> myList2 = new ArrayList<String>();
Collections.addAll(myList2, "str1","str2","str3","str4","str5");
for(String element : myList2){//ConcurrentModificationException here
if(element.equalsIgnoreCase("str1"))
myList2.remove("str1");
}
System.out.println(myList2);
what is the reason?
I'm seeing the same thing,
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Launcher
{
public static void main(String[] args)
{
doThis();
doThat();
}
private static void doThis()
{
System.out.println("dothis");
try
{
List<String> myList1 = new ArrayList<String>();
Collections.addAll(myList1, "str1","str2","str3","str4","str5");
for(String element : myList1){//no ConcurrentModificationException here
if(element.equalsIgnoreCase("str4"))
myList1.remove("str4");
}
System.out.println(myList1);
}
catch(Exception e)
{
e.printStackTrace();
}
}
private static void doThat()
{
System.out.println("dothat");
try
{
List<String> myList2 = new ArrayList<String>();
Collections.addAll(myList2, "str1","str2","str3","str4","str5");
for(String element : myList2){//ConcurrentModificationException here
if(element.equalsIgnoreCase("str1"))
myList2.remove("str1");
}
System.out.println(myList2);
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
which outputs,
dothis
[str1, str2, str3, str5]
dothat
java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
at java.util.AbstractList$Itr.next(Unknown Source)
at com.foo.Launcher.doThat(Launcher.java:41)
at com.foo.Launcher.main(Launcher.java:12)
And I've found the reason.
Java use a modCount(modification count) and an expectedCount to test whether there is a modification to the list.
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
In both condition, modCount is 6 after the remove, but expectedModCount is 5.
The problem is the hasNext().
public boolean hasNext() {
return cursor != size;
}
The list use a cursor and size to check whether has a next element. And the hasNext() is happend before the checkForComodification because the checkForComodification() is called in the next() method.
public boolean hasNext() {
return cursor != size;
}
#SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
So when you remove the second last element, the cursor=4, and size=4 also. hasNext() return false. Jump out of the loop and print the result.
The actual code that javac builds for for-each is
Iterator<String> i = myList1.iterator();
while(i.hasNext()) {
String element = i.next();
if (element.equalsIgnoreCase("str4"))
myList1.remove("str4");
}
and this is ArrayList Iterator.hasNext implementation
public boolean hasNext() {
return cursor != size;
}
as we can see hasNext() does not check for concurrent modification so when we remove the last but one element the loop ends without noticing the the problem.
Actually it is strange that next() and remove() check for concurrent modification but hasNext() does not. Fail-fast iterator is supposed to detect bugs, but our bug went unnoticed.
This is a commonly occurring issue. StackOverflow has hundreds of threads covering this. You can find the answer to your question here:
How can I iterate over an object while modifying it in Java?
When you remove the second last element, The hasNext() check fails and the loop iteration stops. Check the ArrayList iterator code in JDK.
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayList.java#ArrayList.Itr.hasNext%28%29
But in case of removal of second element the hasNext() check passes and you enter the next() method where the first thing it checks for is modification to the arrayList and hence the exception. Please check this code:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/ArrayList.java#ArrayList.Itr.next%28%29
The safest way is to remove the element using the iterators remove method.
Try debugger to step over the code, for a better understanding of how it works.
Related
This question already has an answer here:
Why iterator.forEachRemaining doesnt remove element in the Consumer lambda?
(1 answer)
Closed 6 years ago.
There is this class
public class IteratorStuff {
private static final String EMPTY = "";
public static void main(String[] args) {
System.out.println("success:");
success(newCollection());
System.out.println("fail:");
fail(newCollection());
}
private static void fail(Collection<String> myCollection) {
Iterator<String> iterator = myCollection.iterator();
iterator.forEachRemaining(new Consumer<String>() {
public void accept(String s) {
if (s != EMPTY)
System.out.println("string = " + s);
else
iterator.remove();
}
});
}
private static Collection<String> newCollection() {
Collection<String> myList = new LinkedList<String>();
myList.add(EMPTY);
myList.add("1");
myList.add("2");
myList.add("3");
return myList;
}
private static void success(Collection<String> myCollection) {
Iterator<String> iterator = myCollection.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
if (s != EMPTY)
System.out.println("string = " + s);
else
iterator.remove();
}
}
}
It iterates over a collections of Strings and removes a particular EMPTY String and prints the others. The success(Collection) implementation works fine.
The fail one breaks with an IllegalStateException. However, it is able to get the EMPTY String from the iterator. That suggests that next() must have been called. Also, in the default forEachRemaining implementation
default void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (hasNext())
action.accept(next());
}
next() is called and what ever element is passed to action.accept(). On a side not I also cannot seem to find the implementation of the Iterator returned by LinkedList.
Is this a bug? How can the first element be returned and still cause an IllegalStateException?
Also, this only happens if the first element is the EMPTY String.
For future readers: THIS ANSWER IS INCORRECT!
Even though the asker has accepted this answer as solution to their problem, it may not work [for others or in general]. Please see this answer by Andreas for a more thorough analysis of the problem.
If you look at the code for LinkedList$ListItr (the ListIterator implementation returned by LinkedList#iterator()) in GrepCode you'll see that it does not update the iterator itself, it starts from the current element and does the iteration using local variables.
This means that the iterator itself, on which you never called next() is invalid. Even if you did call next() prior to entering the loop, it would remove the wrong element(s), and also probably cause ConcurrentModificationException as its position is not updated by forEachRemaining() and item removal would interfere with the iterator.
<soapbox>
For any question about the Java libraries not resolvable from the Javadoc, GrepCode is the go-to resource. Use it.
</soapbox>
The problem is that you're using a LinkedList, and it has it's own flawed implementation of forEachRemaining().
Source:
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (modCount == expectedModCount && nextIndex < size) {
action.accept(next.item);
lastReturned = next;
next = next.next;
nextIndex++;
}
checkForComodification();
}
With the default implementation, the accept() method wouldn't be called until after next() returns.
public E next() {
checkForComodification();
if (!hasNext())
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.item;
}
Since remove() checks the value of lastReturned, that value needs to be set before called accept().
public void remove() {
checkForComodification();
if (lastReturned == null)
throw new IllegalStateException();
Node<E> lastNext = lastReturned.next;
unlink(lastReturned);
if (next == lastReturned)
next = lastNext;
else
nextIndex--;
lastReturned = null;
expectedModCount++;
}
As already mentioned, the forEachRemaining() implementation is bugged. It should be:
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
while (modCount == expectedModCount && nextIndex < size) {
lastReturned = next;
next = next.next;
nextIndex++;
action.accept(lastReturned.item);
}
checkForComodification();
}
File a bug!
Update
ArrayList$Itr.forEachRemaining() has a similar problem, were cursor and lastRet is not set during iteration, so although javadoc of forEachRemaining() doesn't explicitly say you cannot use Iterator.remove() or ListIterator.add(), the current implementations obviously didn't expect that you would.
They don't even fail or guard in a consistent manner, so they are not consistent with normal fail-fast policy.
So perhaps filing a bug for documentation and/or fail fast logic would be more appropriate.
The problem might be -
you are working on iterator and concurrently modifying it.
private static void fail(Collection<String> myCollection) {
Iterator<String> iterator = myCollection.iterator();
iterator.forEachRemaining(new Consumer<String>() {
public void accept(String s) {
if (s != EMPTY)
System.out.println("string = " + s);
else
iterator.remove();
}
});
}
you are calling forEachRemaining method using iterator object and inside that you are also removing the object from same iterator.
I am trying to create hasnext() has next() methods for a iterator so that the output of a collection will be:
"printing","elements","in","order","from","collection"
input:
[A] - ["printing", "elements", "in"]
[B] - ["order"]
[C] - ["from", "collection"]
At the moment I have my methods looking like:
public MyIterator(Collection<Collection<Object>> myColl) {
_myColl = myColl;
}
public boolean hasNext() {
if(myColl.next != null)
{
return true
}
return !queue.isEmpty();
}
public Object next() throws java.util.NoSuchElementException {
//Dont really know what to put in here....
}
Any pointers would be appreciated
The best way to do is declare a counter and increment when you are accessing the has next. In the logic if i will express, then that will be like this.
private int counter = 0;
public boolean hasNext(){
counter = counter < collection.size()? counter + 1: counter;// increment
return counter < collection.size();// check and give the appropriate boolean value
}
public T next(){
return collection.get(counter);// to get the counter number of element
}
where counter is the private variable in the class and T is the generic type on which type of object the collection is build up. like
Collection<String>
This answer is all about logic. it may or may not contain the exact code.
Well, i don't understand your question really.. why you can't just use the normal iterator?
I will say to you how to create a basic iterator, to let you understand how things works in basic then adapt your solution:
Suppose we need to iterate over a List<T> and you want to create an helper class to do it.
class ListIterator<T>
You need two private fields
The list to iterate
The pointers to the last item
and 3 methods + 1 constructor
hasNext() -> Boolean, returns true if there are more items to iterate
next() -> Return the next element in the list
reset() -> Reset the interal pointer
constructor -> Just takes as argument the list to iterate
How will look the fields?
private final List<T> list; // The list where this call will iterate
private int pointer; // The pointer to the next iterable item
As said in the description, the constructor will take the reference to the list so it will just be
public ListIterator(List<T> list)
{
this.list = list;
pointer = 0;
}
save the reference and set pointer to 0 (start).
Let's talk about the methods:
hasNext should check if our current pointer has reached the size of the list.
So it will just be (pointer != list.size())
public boolean hasNext()
{
return (pointer != list.size());
}
Will be true if more items are avaitable, false otherwise.
next return the next item if any. Could be simplified by using our hasNext method so it will be
public T next()
{
if (!hasNext())
throw new NoSuchElementException("no field");
return list.get(pointer++);
}
Things to notice:
T is the return because our list is type T
list.get(pointer++) we first get the item from the list in position pointer then we add 1 to the pointer
The reset method is just a pointer = 0.
public void reset()
{
pointer = 0;
}
How to use it?
Like other iterators, create a new object of type ListIterator and pass the list to iterate.
List<String> test = new ArrayList<String>();
test.add("Hello");
test.add("World");
test.add("Whatsapp");
ListIterator<String> iterator = new ListIterator<String>(test);
while (iterator.hasNext())
{
System.out.println(iterator.next());
}
This question already has answers here:
Avoiding NullPointerException in Java
(66 answers)
Closed 6 years ago.
How to avoid null insertion in ArrayList while inserting element?
ArrayList<String> al=new ArrayList<String>();
al.add(null);//should avoid
.
.
.
al.add("Ramesh");
Avoiding null can be harmful sometimes and it could hide possible bugs.
If you're worried about getting NullPointerException in some stage, you can simply check if the item stored in the ArrayList is null.
You cannot disallow inserting null to ArrayList.
You can try something like that, But if you want to do exactly what you are trying you have to rewrite add() in ArrayList class. Using this validation you can avoid null
public static void main(String[] args) {
ArrayList<String> al=new ArrayList<String>();
al=add(al,null);
al=add(al,"Ramesh");
al=add(al,"hi");
}
public static ArrayList<String> add(ArrayList<String> al,String str){
if(str!=null){
al.add(str);
return al;
}else {
return al;
}
}
In this case you have to call your custom add method to add element
You could create your own ArrayList-Class (derived from the original) and override the Add-Method
Then you could check for null when Adding.
#Override
public boolean add(E e) {
if (e == null) return false;
else return super.add(e)
}
As Mark stated in the comments you perhaps want to override all other possibilties of Adding values too. (see the doc)
add(E e)
add(int index, E element)
addAll(Collection c)
addAll(int index, Collection c)
set(int index, E element)
ArrayList<String> al = new ArrayList<String>() {
#Override
public boolean add(String s ) {
if( s != null ) {
return super.add( s );
}
return false;
}
};
al.add(null);
al.add("blabla");
I am working on a Linked Lists assignment for my OOP class, and have run into some trouble with a remove method. Our professor has asked us to write a method:
public Object removeElement(int index)
This takes an index, which is the location of the element that needs removed. It must return the data the deleted node contained as well. However, I am having trouble with getting the method to return the object it is removing. For some reason I keep getting the error that the method must return a result of type object. I have it returning an object, and I've gone through trial and error in various spots with no success.
Here is my code:
public Object removeElement(int index)
{
ListIterator iterator = listIterator();
Object object;
//If the supplied index is less than zero, throw an exception.
if(index < 0)
{
IndexOutOfBoundsException ex = new IndexOutOfBoundsException();
throw ex;
}
else
{
for(int i = 0; i <= index; i++)
{
if(!iterator.hasNext())
{
IndexOutOfBoundsException ex = new IndexOutOfBoundsException();
throw ex;
}
else
{
if(i == index)
{
object = iterator.next();
iterator.remove();
return object;
}
else
{
iterator.next();
}
}
}
}
}
You have it returning an object if i == index. But the compiler doesn't know that the loop will actually always end at that point. It's looking at the bottom of the loop and thinking "What do we want to return if we get here?"
I would actually restructure your code to:
if (index < 0)
{
// No need for a separate variable
throw new IndexOutOfBoundsException();
}
// No need for an else block
ListIterator iterator = listIterator();
Object current = null;
for (int i = 0; i <= index; i++)
{
// Note: assuming you expose the size(), you could check this up front...
if(!iterator.hasNext())
{
throw new IndexOutOfBoundsException();
}
current = iterator.next();
}
iterator.remove();
return current;
Now you always call remove and return when you've called next() the given number of times, because that's when the loop will end other than via an exception.
Firstly do not use iterator from java LinkedList it is Doubly linked list , I think professor wants to see how you implement remove functionality for LikedList data structure.
Secondly make loop and condition where i+1 == index in this place, save current element for return like Node returnElement = curent.next; and make delete manipulation curent.next = curent.next.next;
Pls post listIterator() method implementation and the error message that you are getting.
Note:> You have to manage the size of the list using an class variable such as an integer. So you dont have check !iterator.hasNext(), instead compare index with current size.
Why Methode LinkedList.contains() runs quickly than such implementation:
for (String s : list)
if (s.equals(element))
return true;
return false;
I don't see great difference between this to implementations(i consider that search objects aren't nulls), same iterator and equals operation
Let's have a look at the source code (OpenJDK version) of java.util.LinkedList
public boolean contains(Object o) {
return indexOf(o) != -1;
}
public int indexOf(Object o) {
int index = 0;
if (o==null) {
/* snipped */
} else {
for (Entry e = header.next; e != header; e = e.next) {
if (o.equals(e.element))
return index;
index++;
}
}
return -1;
}
As you can see, this is a linear search, just like the for-each solution, so it's NOT asymptotically faster. It'd be interesting to see how your numbers grow with longer lists, but it's likely to be a constant factor slower.
The reason for that would be that this indexOf works on the internal structure, using direct field access to iterate, as opposed to the for-each which uses an Iterator<E>, whose methods must also additionally check for things like ConcurrentModificationException etc.
Going back to the source, you will find that the E next() method returned by the Iterator<E> of a LinkedList is the following:
private class ListItr implements ListIterator<E> {
//...
public E next() {
checkForComodification();
if (nextIndex == size)
throw new NoSuchElementException();
lastReturned = next;
next = next.next;
nextIndex++;
return lastReturned.element;
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
This is considerably "busier" than the e = e.next; in LinkedList.contains! The iterator() of a LinkedList is actually a ListIterator, which has richer features. They aren't needed in your for-each loop, but unfortunately you have to pay for them anyway. Not to mention all those defensive checks for ConcurrentModificationException must be performed, even if there isn't going to be any modification to the list while you're iterating it.
Conclusion
So yes, iterating a LinkedList as a client using a for-each (or more straightforwardly, using its iterator()/listIterator()) is more expensive than what the LinkedList itself can do internally. This is to be expected, which is why contains is provided in the first place.
Working internally gives LinkedList tremendous advantage because:
It can cut corners in defensive checks since it knows that it's not violating any invariants
It can take shortcuts and work with its internal representations
So what can you learn from this? Familiarize yourself with the API! See what functionalities are already provided; they're likely to be faster than if you've had to duplicate them as a client.
I decided to test this and came out with some interesting result
import java.util.LinkedList;
public class Contains {
private LinkedList<String> items = new LinkedList<String>();
public Contains(){
this.addToList();
}
private void addToList(){
for(int i=0; i<2000; i++){
this.items.add("ItemNumber" + i);
}
}
public boolean forEachLoop(String searchFor){
for(String item : items){
if(item.equals(searchFor))
return true;
}
return false;
}
public boolean containsMethod(String searchFor){
if(items.contains(searchFor))
return true;
return false;
}
}
and a JUnit testcase:
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class ContainsTest {
#Test
public void testForEachLoop(){
Contains c = new Contains();
boolean result = c.forEachLoop("ItemNumber1758");
assertEquals("Bug!!", true, result);
}
#Test
public void testContainsMethod(){
Contains c = new Contains();
boolean result = c.containsMethod("ItemNumber1758");
assertEquals("Bug!!", true, result);
}
}
This funny thing is when I run the JUnit test the results are :
- testForEachLoop() - 0.014s
- testContainsMethod() - 0.025s
Is this true or I am doing something wrong ?