java while (LinkedList.iterator().hasNext()) does not work - java

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

Related

Iteration is quit after first iteration

I am trying to compare two different List and remove the duplicates. However, the two lists have two different object types and only common attribute is app name.
Here is the code,
public List<TvAppsType> getAvailableAppsTypesByCompanyIdSecond(int comapnyId) {
// put apps to the model that belong to the given company id
TVAppService tvAppService = new TVAppService();
List<ThreatviewApp> apps = new CopyOnWriteArrayList<ThreatviewApp>();
apps = tvAppService.getAllAppsforCompanyId(comapnyId);
// get list of app types
TvAppTypeService types = new TvAppTypeService();
List<TvAppsType> apptypes = new CopyOnWriteArrayList<TvAppsType>();
apptypes = types.getAppTypes();
// add the items to collection for removing
for(TvAppsType app : apptypes){
System.out.println("-----------------------");
System.out.println("app : " + app.getAppType_name());
}
Iterator<TvAppsType> itertypes = apptypes.iterator();
Iterator<ThreatviewApp> it = apps.iterator();
while (itertypes.hasNext()) {
TvAppsType apptype = itertypes.next();
while (it.hasNext()) {
ThreatviewApp tvapp = it.next();
if (tvapp.getApp_name().trim().equals(apptype.getAppType_name().trim())) {
itertypes.remove();
}
}
}
for(TvAppsType app : apptypes){
System.out.println("-----------------------");
System.out.println("app : " + app.getAppType_name());
}
return apptypes;
}
Problem is this works only in first iteration, I suspect that after the List is modified, the iteration behavior is unspecified.
void remove() Removes from the underlying collection the last element
returned by this iterator (optional operation). This method can be
called only once per call to next(). The behavior of an iterator is
unspecified if the underlying collection is modified while the
iteration is in progress in any way other than by calling this method.
As I am trying to modify the lists runtime, I used CopyOnWriteArrayList
bascically, I followed this article article
why the iteration stop after first one? How to fix this and remove all duplicates?
In addition to #Eran's answer, you have another problem. Once you have removed a TvAppsType (in the inner while loop), you should never attempt to remove the same object again. Also, quitting the inner loop as soon as possible will speed up your algorithm.
So, the inner loop should look like this:
while (it.hasNext()) {
ThreatviewApp tvapp = it.next();
if (tvapp.getApp_name().trim().equals(apptype.getAppType_name().trim())) {
itertypes.remove();
break;
}
}
You have to reset the iterator of the inner loop if you wish to iterate more than once on the apps list. Otherwise, the inner while loop will iterate over the apps list only one time, after which it.hasNext() will be false.
Iterator<TvAppsType> itertypes = apptypes.iterator();
while (itertypes.hasNext()) {
TvAppsType apptype = itertypes.next();
Iterator<ThreatviewApp> it = apps.iterator(); // the inner iterator must be
// initialized in each iteration
// of the outer loop
while (it.hasNext()) {
...

Why does the Iterator not "Move Next" in a for loop

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());
}

change a list while iterating or using a for each loop

I am trying to iterate (or use a for each loop) on a Linked list class and be able to change the item (when found) to a passed in parameter.
for(Item n : items)
{
if (n.getKey().equals(key))
{
n = new Item(key, value);
}
}
Does this change of data work or is it temporary (only to be lost when the activation record is deleted)?
You can't iterate over a collection and modify it. You will always get a java.util.ConcurrentModificationException. First off all you need to use an iterator, to remove the item. Then you can use a second list to store the data you want to add.
Here you are an example:
LinkedList<String> linkedList = new LinkedList<String>();
linkedList.add("This");
linkedList.add("is");
linkedList.add("an");
linkedList.add("test");
LinkedList<String> temp = new LinkedList<String>();
for (Iterator<String> iterator = linkedList.iterator(); iterator.hasNext();) {
String string = (String) iterator.next();
if(string.equals("an")) {
iterator.remove();
temp.add("a");
}
}
linkedList.addAll(temp);
You can call iterator.remove() to savely remove the current item from list.
You are using fast enumeration, which protects the list that you are iterating through. If you would like to change the data in the list, you would need to use a traditional for loop.
Basically how fast enumeration works is it makes the array read-only in the block of code because you have no access to what integer the iteration is.
You could do this:
for(int i = 0; i < items.length; i++)
{
if (n.getKey().equals(key))
{
items[i] = new Item(key, value);
}
}

How to fix java.util.ConcurrentModificationException error when trying traverse in ArrayList

I'm trying to add new object to my ArrayList if it satisfy the condition.
But it got me this ConcurrentModificationExeption when I tried to run it. Hope you could help me:
public void addTaskCollection(Task t){
ListIterator<Task> iterator = this.taskCollection.listIterator();
if(this.taskCollection.isEmpty())
this.taskCollection.add(t);
while (iterator.hasNext()){
if(t.isOverlapped(iterator.next()))
this.taskCollection.add(t);
}
}
And here is the exeption error
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:819)
at java.util.ArrayList$Itr.next(ArrayList.java:791)
at Diary.addTaskCollection(Diary.java:36)
at Test.main(Test.java:50)
Java Result: 1
Replace your code with:
ListIterator<Task> iterator = this.taskCollection.listIterator();
boolean marker = false;
if(taskCollection.isEmpty())
this.taskCollection.add(t);
else {
while (iterator.hasNext()) {
if(iterator.next().isOverlapped(t) == false)
marker = true;
}
}
if (marker == true)
taskCollection.add(t);
to avoid ConcurrentModificationException.
copy the array and change the original.
It seems you encounter a race condition. Multiple threads are accessing / modifying the same collection. Use a thread-safe List implementation.
Also, you must not modifying the collection (adding / removing) while iterating on it with an Iterator.
EDIT
ConcurrentModificationExeption sounds like taskCollection is accessed and modified by multiple threads at the same time (we can not say regarding the piece of code you provide if your program is single or multi threaded). If you share taskCollection between several threads, use a thread-safe list implementation.
But, the error here is actually clearly due to the fact that you add an element to the collection between the moment you get an iterator on it and the moment you use this iterator. To fix that copy the new elements in temporary list and add them all in once at the end of the iteration.
Re-formatted Truong's answer from comments:
ListIterator<Task> iterator = this.taskCollection.listIterator();
boolean marker = false;
if(taskCollection.isEmpty())
this.taskCollection.add(t);
else {
while (iterator.hasNext()) {
if(iterator.next().isOverlapped(t) == false)
marker = true;
}
if (marker == true)
taskCollection.add(t);
}
Maintain two iterators.
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Example_v3 {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
// Insert some sample values.
list.add("Value1");
list.add("Value2");
list.add("Value3");
// Get two iterators.
Iterator<String> ite = list.iterator();
Iterator<String> ite2 = list.iterator();
// Point to the first object of the list and then, remove it.
ite.next();
ite.remove();
/* The second iterator tries to remove the first object as well. The object does
* not exist and thus, a ConcurrentModificationException is thrown. */
ite2.next();
ite2.remove();
}
}

Delete element oh HashSet inside for

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);

Categories