If I create a new object the program is working properly:
Iterator iter = Students.iterator();
while (iter.hasNext()){
Student newstudent=(Student) iter.next();
if (newstudent.getCourse()==2){
System.out.println( newstudent.getName());}
But if do not like to:
Iterator iter = Students.iterator();
while (iter.hasNext()){
if (((Student) iter.next()).getCourse()==2){
System.out.println(( (Student)iter.next()).getName());}//Here it is printing out the next object afther that I have checked
How to stay by the same object?
Save the current student temporarly:
Iterator iter = Students.iterator();
while (iter.hasNext()){
Student currentStudent = (Student) iter.next()
if (currentStudent.getCourse()==2) {
System.out.println(currentStudent.getName());
} //Here it is printing
}
If you don't want to advance the iterator you could always consider using a PeekingIterator, which allows you to peek at the next element without removing it, e.g.:
final Iterator<Student> iter = Iterators.peekingIterator(Students.iterator());
final Student a = iter.peek();
final Student b = iter.peek();
final Student c = iter.next();
assert a == b == c;
The PeekingIterator is included in Google's Guava library, although it would be easy to roll your own.
You need to call next() method only once
while (iter.hasNext()){
Student student = (Student) iter.next();
if (student.getCourse()==2){
System.out.println(( student.getName());
}
if (((Student) iter.next()).getCourse()==2){ //first time next happened
System.out.println(( (Student)iter.next()).getName());}/ after condition next happened again
In short You are checking condition on N and printing the value on N+1(N.next).
What ever you are doing in first approach is the correct one.
Because in later case you are invoking iterator.next() twice. The next() call returns the current element pointed by iterator and moves the cursor to next element. So in your case
Iterator iter = Students.iterator();
while (iter.hasNext()){
if (((Student) iter.next()).getCourse()==2){ //--> Student 1 is returned by next() call and iterator points to Student 2 (next in the list)
System.out.println(( (Student)iter.next()).getName());} //--> Student 2 is returned by next() call
its good practice to store the element returned by iterator.next() at the beginning of the loop as you did in your first example, to avoid unexpected behaviors
Whenever you call iter.next() the current index of iterator is moving forward. So it is required to save the current Student object in temporary object.
Initially
-|
[-][-][-][-]
iter.next()
---|
[-][-][-][-]
if you call iter.next() twise from here
---------|
[-][-][-][-]
Consider each [-] is student object
You are calling iter.next() twice in your program. Hence the error!
Related
I have a Collection<T>, named "col". Not important what contains the class T. When I iterate the collection, at each iteration I need to have the current element and the next.
Iterator it = col.iterator();
while (it.hasNext()) {
T line = (T) it.next();
T nextLine = it.hasNext()? NEXT_LINE : null;
// more Java code with line and nextLine
}
"NEXT_LINE" is not a declared constant, but an invalid code. I need to replace it with a valid Java code that returns the next element from the collection, without incrementing again the iterator.
I found this link:
Java iterator get next without incrementing
The weakness of this solution, in my case, is if the collection contains only 1 element, I have to do too many changes in my code. If there is a solution for my version, the case with 1 element is covered, because nextLine is null.
I can also convert the collection in an ArrayList, but I'll do this only when I consider there is not a better way:
ArrayList<T> list = new ArrayList<T>(col);
for (int i=0; i<list.size(); i++) {
T line = list.get(i);
T nextLine = i<list.size()-1 ? list.get(i+1) : null;
// more Java code with line and nextLine
}
Guava contains the PeekingIterator interface, which could be your solution.
PeekingIterator it = Iterators.peekingIterator(col.iterator());
while (it.hasNext()) {
T line = (T) it.next();
T nextLine = it.hasNext()? it.peek() : null;
}
More information here. Seems to match your current structure well.
The usage for Iterator is as follows (1 it.hasNext() and 1 it.next()).
Iterator<T> it = col.iterator();
T previous = null;
if (it.hasNext()) {
previous = it.next();
while (it.hasNext()) {
T next = it.next();
// ... previous ... next ..
previous = next;
}
}
I'm learning to iterate, and have implemented an Iterator on my 'CStickChart' Class using the following private property:
private List<CStick> cStickCollection = new ArrayList<CStick>();
and then implementing the method to return CSticks:
public Iterator<CStick> iterator() {
return this.cStickCollection.iterator();
}
Now when I try and iterate through it, I'm able to do so with the assigned localCStick but calling the next() method on the CStickChart Iterator doesn't do what I expected it to. I expected it to give me the next CStick in my CStickChart (hence when I call the getEPIC I was expecting it to give me the next EPIC along).
// Print the EPIC out of the Array using the iterator
for (CStick localCStick : testCStickChart) {
System.out.println(localCStick.getEPIC());
//The below line doesn't return the next CStick and I'm not sure why
System.out.println("next EPIC is " + testCStickChart.iterator().next().getEPIC());
}
Please could someone explain why this is not the case (it always returns the first EPIC)
System.out.println("next EPIC is " + testCStickChart.iterator().next().getEPIC());
This happens because in this line you are getting a new iterator in every iteration of the loop. Each new iterator starts from the beginning of the list again.
It sounds like you don't want to use the enhanced-for structure. The reason: an enhanced-for with an iterable entity will use the iterator provided internally, and will only ever advance forward.
This also means that any calls to a iterator while inside that loop produce an iterator that starts at the beginning of iteration.
So, with that, you have two options - both of which involve abandoning the enhanced-for:
Use a standard for loop with indexing to advance backwards and forwards with the list, or
Use a ListIterator as provided by List to move backwards and forwards in a very seamless way.
Here is an example with using integers - note that every time I advance the iterator I have to move it back to its previous spot so that I don't double-advance it. Also, I have a condition to break out of the loop once we've run out of elements.
List<Integer> integerList = new ArrayList<Integer>() {{
add(1);
add(2);
add(3);
add(4);
add(5);
add(6);
add(7);
add(8);
add(9);
add(10);
}};
for (ListIterator<Integer> iterator = integerList.listIterator(); iterator.hasNext(); ) {
int value = iterator.next();
int nextValue = Integer.MIN_VALUE;
if (iterator.hasNext()) {
nextValue = iterator.next();
// Reset the state of the iterator
iterator.previous();
}
System.out.println("Value = " + value);
if(nextValue != Integer.MIN_VALUE) {
System.out.println("Next value = " + nextValue);
}
}
Because you are getting the top iterator of cStickCollection with .iterator(). I think you wanted to use the same iterator position as you're at in your loop, and peek at the next element. You can't do that with a for-each loop and you also can't do that with an Iterator in general (because they don't implement a peek).
Instead, you could use a traditional for loop on your cStickCollection like
for (int i = 0, len = cStickCollection.size(); i < len; i++) {
CStick localCStick = cStickCollection.get(i);
System.out.println(localCStick.getEPIC());
if (i + 1 < len) { // <-- check that there is a "next"
System.out.println("next EPIC is "+cStickCollection.get(i+1).getEPIC());
}
}
Everytime you call testCStickChart.iterator() inside of that loop, you create a new iterator object. So each call to next() is carried out on a new iterator object, returning the first object. What you want to do is to declare a new Iterator<CStick> just before the loop and use it inside the loop, like so:
Iterator<CStick> it = testCStickChart.iterator();
// Print the EPIC out of the Array using the iterator
for (CStick localCStick : testCStickChart) {
System.out.println(localCStick.getEPIC());
//The below line doesn't return the next CStick and I'm not sure why
System.out.println("next EPIC is " + it.next().getEPIC());
}
I have the following while loop, if I put this.boatTripsList.iterator().hasNext() in the while loop condition, it throws error. When I create iterator then put in the while loop condition, it will work then. Why is this? Thanks & Regards. (the second version throws error)
public Journey(List<BoatTrip> trips) {
this.boatTripsList = new LinkedList<BoatTrip>();
Iterator<BoatTrip> iterator = trips.iterator();
//add the given boat trips to the boattrips list
while (iterator.hasNext()) {
BoatTrip thistrip = iterator.next();
this.boatTripsList.add(thistrip);
}
}
public Journey(List<BoatTrip> trips) {
this.boatTripsList = new LinkedList<BoatTrip>();
//add the given boat trips to the boattrips list
while (trips.iterator().hasNext()) {
BoatTrip thistrip = iterator.next();
this.boatTripsList.add(thistrip);
}
}
This is normal: if your while condition is while(trips.iterator().hasNext()), you create a new iterator each time. If your list is not empty, the condition will therefore always be true...
While in the loop itself, you use the iterator you created before entering the loop... As a result, you'll get a NoSuchElementException when this iterator is empty.
Use:
final Iterator<Whatever> = list.iterator();
Whatever whatever;
while (iterator.hasNext()) {
whatever = iterator.next();
// do whatever stuff
}
But for walking lists, a foreach loop is preferred:
for (final BoatTrip trip: tripList)
// do whatever is needed
And if you want to add the contents of a list to another, use .addAll():
// no need for the "this" qualifier, there is no name conflict
boatTripList.addAll(trips);
You aren't using the iterator you requested on the first line of your code there - you're requesting a new one each time, so it will always have a next.
A call to .iterator() obtains a new iterator. If you do that in the loop, you will always obtain a new iterator rather than iterating over an existing iterator.
this.boatTripsList.iterator().hasNext() is wrong
this.boatTripsList.hasNext() is correct
Im playing around with some code for my college course and changed a method from
public boolean removeStudent(String studentName)
{
int index = 0;
for (Student student : students)
{
if (studentName.equalsIgnoreCasee(student.getName()))
{
students.remove(index);
return true;
}
index++;
}
return false;
}
To:
public void removeStudent(String studentName) throws StudentNotFoundException
{
int index = 0;
for (Student student : students)
{
if (studentName.equalsIgnoreCase(student.getName()))
{
students.remove(index);
}
index++;
}
throw new StudentNotFoundException( "No such student " + studentName);
}
But the new method keeps giving a Concurrent Modification error. How can I get round this and why is it happening?
It is because you continue traversing the list after performing remove().
You're reading and writing to the list at the same time, which breaks the contract of the iterator underlying the foreach loop.
Use Iterator.remove()
for(Iterator<Student> iter = students.iterator(); iter.hasNext(); ) {
Student student = iter.next();
if(studentName.equalsIgnoreCase(student.getName()) {
iter.remove();
}
}
It is described as the following:
Returns the next element in the iteration.
Throws NoSuchElementException if the iteration has no more elements.
You can use Iterator.hasNext() to check if there is a next element available.
foreach construct uses an underlying Iterator.
In the second method you continue to iterate even after removing an item from the list. This is resulting in the exception that you see. Take a look at this statement taken from ConcurrentModificationException documentation:
For example, it is not generally permissible for one thread to modify
a Collection while another thread is iterating over it. In general,
the results of the iteration are undefined under these circumstances.
Some Iterator implementations (including those of all the general
purpose collection implementations provided by the JRE) may choose to
throw this exception if this behavior is detected.
You are not allowed to remove an element from your collection while you iterate over it. The iterator detects a structural change during its usage, and throws the exception. Many collections are implemented in such a way.
Use the iterator directly instead:
Iterator<Student> it = students.iterator();
while (it.hasNext()) {
Student student = it.next();
if (studentName.equalsIgnoreCase(student.getName())) {
it.remove();
return true;
}
}
return false;
you can avoid concurrent modification error buy just breaking the loop after removing the element or if the method has a return type return a value after removing the element.
This error occurs because you are trying to alter the size of a collection while you are iterating it. If you have 10 students, you start your loop expecting to go through 10 iterations. When you remove a student, how many iterations do still need to go? The answer obviously depends on where you removed your student from the list and where you currently are in your iteation. Obviously, java cannot know this.
To get around this, you must use an iterator. You can accomplish this as follows:
Iterator<Student> studentsIterator;
for(studentsIterator = students.iterator(); studentsIterator.hasNext();)
{
Student student = studentsIterator.next();
if(student... /* condition */)
{
studentIterator.remove(); //This removes student from the collection safely
}
}
You are not allowed to remove an element from students collection while iterating through it.
This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.
For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it. In general, the results of the iteration are undefined under these circumstances.
http://docs.oracle.com/javase/6/docs/api/java/util/ConcurrentModificationException.html
Try changing to
Iterator<Student> itr = students.iterator();
while (itr.hasNext()) {
Student student = itr.next();
if (studentName.equalsIgnoreCase(student.getName()))
{
itr.remove();
}
}
If you want to remove inside a loop you should use an iterator and its remove method
public boolean removeStudent(String studentName)
{
Iterator<Student> itS = students.iterator();
while(itS.hasNext())
{
Student student = itS.next();
if (studentName.equalsIgnoreCasee(student.getName()))
{
itS.remove();
return true;
}
}
return false;
}
You shouldn't delete objects from a collection while using
a for-each statement - this will cause exceptions as your iterator faces a changed collection in the course of its iterations. (the for loop)
either use a regular for loop (for int i = 0; i < 100; i++) etc...
or keep the objects to remove in a list, and remove them outside of the for loop.
Also, you remove the object by index where index is : 0 , 1 , 2
but index should actaully be the index of the student.
i want to through a HashSet with for (MyClass edg : myHashSet) and inside for, i want to delete an element for my HashSet.
for (MyClass edg : myHashSet)
{
if(....)
myHashSet.remove();
}
but there are an error java.util.ConcurrentModificationException how can I delete an element of a set during a parcour ?
Instead of using the modified for loop, you can use an Iterator. Iterators have a remove method that lets you remove the last element returned by Iterator.next().
for (final java.util.Iterator<MyClass> itr = myHashSet.iterator(); itr.hasNext();) {
final MyClass current = itr.next();
if(....) {
itr.remove();
}
}
Read the javadoc:
The iterators returned by this class's iterator method are fail-fast: if the set is modified at any time after the iterator is created, in any way except through the iterator's own remove method, the Iterator throws a ConcurrentModificationException.
Use an Iterator and its remove() method.
MyClass edg
Iterator<MyClass> hashItr = myHashSet.iterator();
while ( hashItr.hasNext() ) {
edge = hashItr.next();
if ( . . . )
hashItr.remove();
}
Had a bit of a think, been a while since I did java but another bog standard way to do this is as follows:
Set<Person> people = new HashSet<Person>();
Set<Person> peopleToRemove = new HashSet<Person>();
// fill the set of people here.
for (Person currentPerson : people) {
removalSet.add(currentPerson);
}
people.removeAll(peopleToRemove);