Java Iterator going in infinite while loop - java

I am trying to iterate list with the iterator in while, for some reason its going in infinite.
here is the code
{
List<Person> Person1 = new ArrayList<Person>();
Person p1 = new Person("Name1", "Virginia");
Person1.add(new Person("Nae2", "Virginia"));
printerlist(Person1);
printerlist(p1);
}
private static void printerlist(List<Person> p) {
/*
* print the list
*/
while (p.iterator().hasNext()) {
System.out.println(p.iterator().next().getCity());
}
}

Think about what this line is doing:
while (p.iterator().hasNext()) {
Each time you want to evaluate the condition, you're getting a new iterator object, that has never been touched before.
Since you've never consumed anything from the new iterator, hasNext() will always be true.
Likewise, on the next line:
System.out.println(p.iterator().next().getCity());
You are getting another new iterator, so calling next() on it will always return the first item in the list.
In order to loop correctly, you need to reuse the same iterator for the entirety of the loop. You can do this either by explicitly creating and using a single iterator like so:
Iterator<Person> itr = p.iterator();
while (itr.hasNext()) {
System.out.println(itr.next().getCity());
}
or you can use something like an enhanced for-loop and let Java implicitly create and manage the iterator:
while (Person person : p) {
System.out.println(person.getCity());
}
which is functionally equivalent to
for (Iterator<Person> itr = p.iterator(); itr.hasNext();) {
Person person = itr.next();
System.out.println(person.getCity());
}

p.iterator() creates a new Iterator for list p. So cursor always in begin of collection.
Try this:
Iterator<Person> it = p.iterator();
while (it.hasNext()) {
System.out.println(it.next().getCity());
}

Every time you call p.iterator() you will get a new Iterator starting at the first element. Instead you should assign the returned Iterator to a temporary variable.

You do not need to use iterator() this will return object of type iteration(Iterator<T>). It is use for
an interface (part of the Java Collections) that returns the type that was passed to it. The Iterator is used to traverse the list of elements, and remove an element if necessary.
We can captcher that iteration() from p and assign it in to Iterator with using generic <Person>.
You need to create Iterator<> for Person object type and then only need to use while(p.hasNext()) {
If you are using Java 1.5 or above you can use for each(enhanced for) loop to Iterate objects(list) type. Before 1.5 Iterator is used to iterate through lists. Notice Iterator still use.
If you want to know more about iterator() reffer this java doc and this or stackoverflow question.

Related

Java: Creating a getter function which returns an iterator from an array list

I have a class named User I have a class named UserGroup(an arrayList of users) which contains the following:
variables:
private ArrayList<User> users;
private Iterator<User> userIterator;
constructor:
public UserGroup(){
this.users = new ArrayList<>();
}
I'm trying to get the following to work:
public Iterator<User> getUserIterator(){
userIterator = users.iterator();
return userIterator;
}
And I'm hoping that it returns an iterator which I can use to iterate through a UserGroup by using it in the following context, for example:
while(groupOfUsers.getUserIterator().hasNext()) {
System.out.println(groupOfUsers.getUserIterator().next());
}
This is resulting in some terrifying infinite loop, and I honestly don't even understand what my getter method is returning at this point. (java.util.ArrayList$Itr#74a14482)
Any help in getting my head around how I would actually go about creating a getter that works in returning an iterator that I could use to iterate over any UserGroup would be much appreciated.
Don't store the Iterator as a member variable. An Iterator is something you create every time you need to iterate the loop, and you use that local instance to do so. Multiple Iterators on the same list could be in use at the same time. So there's no need to store it in the object.
remove this line..
private Iterator<User> userIterator; // not needed. bad.
then change your getUserIterator() method to this...
public Iterator<User> getUserIterator(){
return users.iterator();
}
Then use the returned instance like this. But don't call getUserIterator again as it will return you a new one, at the start of the list. (This was the cause of the infinite loop)
Iterator<User> iterator = groupOfUsers.getUserIterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
As an advanced step, you can use the enhanced for loop like this..
for (User user : groupOfUsers) {
System.out.println(user);
}
but only if you make your groupOfUsers class implement the Iterable interface. And change the name of the getUserIterator method to iterator()
public class GroupOfUsers implements Iterable<User> {
private ArrayList<User> users;
public Iterator<User> iterator(){
return users.iterator();
}
// etc..
Assign the iterator to a variable first:
Iterator<User> it = groupOfUsers.getUserIterator();
while(it.hasNext()) {
System.out.println(it.next());
}
Otherwise, you are creating a new iterator (pointing to the start of the list) each time you call groupOfUsers.getUserIterator() - and provided the list isn't empty, groupOfUsers.getUserIterator().hasNext() will then always return true.
Your getter is fine. The problem is with how you use the returned iterator.
while(groupOfUsers.getUserIterator().hasNext())
The above code will try to get a new iterator in the beginning of every iteration, so if the group of users is not empty, the loop condition will always be true, and you have an infinite loop.
Do this instead
Iterator<User> iter = groupOfUsers.getUserIterator();
while (iter.hasNext()) System.out.println(iter.next());
Or if you just want to do something with each user in the group and are using Java 8. You can provide a foreach method taking a Consumer<User> argument. Iterator may allow the client to remove an element from the list, and sometimes you don't want that to happen.
public void foreachUser(Consumer<? super User> consumer) {
users.forEach(consumer);
}
groupOfUsers.foreachUser(System.out::println);

Java Iterator infinite loop iterates only the 1st item in hashmap

I am executing a database query, and as result I get a HashMap. I want to iterate through all the results, but I infinitely add the first item from the result to the arraylist.
QueryResult result=engine.query(query,params);
while(result.iterator().hasNext()) {
HashMap res= (HashMap)result.iterator().next();
Node node=(Node)res.get("n");
results.add(new BusyProfile(node));
}
How to iterate through each object and why do I have infinite loop? Thanks!
Everytime you call result.iterator(), a new Iterator is created, pointing to the first item.
So create it before your loop:
Iterator<?> it = result.iterator();
while (it.hasNext()) {
HashMap res = (HashMap)it.next();
//...
}
You are overwriting your iterator! When result.iterator() is called, you create your iterator but on each iteration, it's creating a new one and it continues to point to the beginning - causing the infinite loop.
What you need to do in this case is save the iterator and then use it to move through the collection.
QueryResult result = engine.query(query,params);
//Save iterator
Iterator i = result.iterator();
while(i.hasNext()) {
HashMap res = (HashMap)i.next();
Node node = (Node)res.get("n");
results.add(new BusyProfile(node));
}
Before you can access a collection through an iterator, you must
obtain one. Each of the collection classes provides an iterator( )
method that returns an iterator to the start of the collection. By
using this iterator object, you can access each element in the
collection, one element at a time.
In general, to use an iterator to cycle through the contents of a
collection, follow these steps −
Obtain an iterator to the start of the collection by calling the
collection's iterator( ) method.
Set up a loop that makes a call to hasNext( ). Have the loop iterate
as long as hasNext( ) returns true.
Within the loop, obtain each element by calling next( ).
There is a quick tutorial here:
https://www.tutorialspoint.com/java/java_using_iterator.htm
All answers posted before mine explained that result.iterator() will instantiate a new iterator each time it is invoked.
And it makes not sense to create an iterator during each iteration for the same iterator that you are iterating with : while(result.iterator().hasNext()) {
.It is right.
Beyond this misuse of the Iterator, you should read the javadoc of the class you are using. It may often help you to create a more effective code.
According to the javadoc of org.neo4j.ogm.session.result.QueryResult, the
QueryResultclass implements the Iterable interface in this way Iterable<Map<String,Object>>.
So instead of doing thing more complicated than required, just use an enhanced for.
It would produce a shorter and more readable code.
Besides, using the more restricted scope for a variable is better as it prevents to use it unsuitably.
With the enhanced for, you don't need any longer to declare the iterator before the loop.
It will be used in the compiled class (as enhanced for uses under the hood an iterator) but it will be restricted to the scope of the loop.
So you should really consider this way :
QueryResult result = engine.query(query,params);
for (Map<String,Object> currentMap : result) {
Node node = (Node) currentMap.get("n");
results.add(new BusyProfile(node));
}
You should call the iterator() method once and then store (and use) the returned value.
Reuse the Iterator
Iterator i = result.iterator();
if(i.hasNext()) {
HashMap res= (HashMap)i.next();
Node node=(Node)res.get("n");
results.add(new BusyProfile(node));
}

Collision Detection returns ConcurrentModificationException [duplicate]

This question already has answers here:
Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop
(31 answers)
Closed 8 years ago.
I'm trying to remove some elements from an ArrayList while iterating it like this:
for (String str : myArrayList) {
if (someCondition) {
myArrayList.remove(str);
}
}
Of course, I get a ConcurrentModificationException when trying to remove items from the list at the same time when iterating myArrayList. Is there some simple solution to solve this problem?
Use an Iterator and call remove():
Iterator<String> iter = myArrayList.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}
As an alternative to everyone else's answers I've always done something like this:
List<String> toRemove = new ArrayList<String>();
for (String str : myArrayList) {
if (someCondition) {
toRemove.add(str);
}
}
myArrayList.removeAll(toRemove);
This will avoid you having to deal with the iterator directly, but requires another list. I've always preferred this route for whatever reason.
Java 8 user can do that: list.removeIf(...)
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));
list.removeIf(e -> (someCondition));
It will remove elements in the list, for which someCondition is satisfied
You have to use the iterator's remove() method, which means no enhanced for loop:
for (final Iterator iterator = myArrayList.iterator(); iterator.hasNext(); ) {
iterator.next();
if (someCondition) {
iterator.remove();
}
}
No, no, NO!
In single threated tasks you don't need to use Iterator, moreover, CopyOnWriteArrayList (due to performance hit).
Solution is much simpler: try to use canonical for loop instead of for-each loop.
According to Java copyright owners (some years ago Sun, now Oracle) for-each loop guide, it uses iterator to walk through collection and just hides it to make code looks better. But, unfortunately as we can see, it produced more problems than profits, otherwise this topic would not arise.
For example, this code will lead to java.util.ConcurrentModificationException when entering next iteration on modified ArrayList:
// process collection
for (SomeClass currElement: testList) {
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
}
}
But following code works just fine:
// process collection
for (int i = 0; i < testList.size(); i++) {
SomeClass currElement = testList.get(i);
SomeClass founDuplicate = findDuplicates(currElement);
if (founDuplicate != null) {
uniqueTestList.add(founDuplicate);
testList.remove(testList.indexOf(currElement));
i--; //to avoid skipping of shifted element
}
}
So, try to use indexing approach for iterating over collections and avoid for-each loop, as they are not equivalent!
For-each loop uses some internal iterators, which check collection modification and throw ConcurrentModificationException exception. To confirm this, take a closer look at the printed stack trace when using first example that I've posted:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at TestFail.main(TestFail.java:43)
For multithreading use corresponding multitask approaches (like synchronized keyword).
While other suggested solutions work, If you really want the solution to be made thread safe you should replace ArrayList with CopyOnWriteArrayList
//List<String> s = new ArrayList<>(); //Will throw exception
List<String> s = new CopyOnWriteArrayList<>();
s.add("B");
Iterator<String> it = s.iterator();
s.add("A");
//Below removes only "B" from List
while (it.hasNext()) {
s.remove(it.next());
}
System.out.println(s);
If you want to modify your List during traversal, then you need to use the Iterator. And then you can use iterator.remove() to remove the elements during traversal.
List myArrayList = Collections.synchronizedList(new ArrayList());
//add your elements
myArrayList.add();
myArrayList.add();
myArrayList.add();
synchronized(myArrayList) {
Iterator i = myArrayList.iterator();
while (i.hasNext()){
Object object = i.next();
}
}
One alternative method is convert your List to array, iterate them and remove them directly from the List based on your logic.
List<String> myList = new ArrayList<String>(); // You can use either list or set
myList.add("abc");
myList.add("abcd");
myList.add("abcde");
myList.add("abcdef");
myList.add("abcdefg");
Object[] obj = myList.toArray();
for(Object o:obj) {
if(condition)
myList.remove(o.toString());
}
You can use the iterator remove() function to remove the object from underlying collection object. But in this case you can remove the same object and not any other object from the list.
from here

How do I get information out of the object returned by an iterators next() method?

I want to compare the destination variable (type int) of a person object with the current floor variable (type int) of a lift object. The person objects are located in a ListArray that belongs to the Lift class. I am using the iterator interface to iterate over the ListArray to compare each persons destination with current floor of the lift. The method match(int destination) is used to return true or false.
This is my code that does not work:
Iterator iterator = lift.getOccupants().iterator();
while(iterator.hasNext()){
if(lift.match(iterator.next().getDestination())){
}
The getDestination() method is underlined with the error:
cannot find symbol, method getDestination(), location class Object
next() method return type is Object so you need to type cast it to Person object.
Like
((Person)iterator.next()).getDestination()
Or else you can use Generic List objects like List and get Generic iterator through it.
Iterator<Person> iterator = lift.getOccupants().iterator();
Then you do not need any casting.
Use
Iterator<Occupant> iterator = lift.getOccupants().iterator();
The proper idiom involving the Iterator is not a while, but a for-loop:
for (Iterator<Occupant> it = lift.getOccupants().iterator; it.hasNext();)
if (lift.match(it.next().getDestination())) it.remove();
The advantage of this is keeping the scope of it contained.
Parameterize the iterator and this will work for you
Iterator<Person> iterator = lift.getOccupants().iterator();
while(iterator.hasNext()){
if(lift.match(iterator.next().getDestination())){
}
}
Using Java 8 Stream:
lift.getOccupants().stream()
.filter(o -> lift.match(o.getDestination()))
// ...
Use Generics in java like this:
Iterator<Person> iterator = lift.getOccupants().iterator();
while(iterator.hasNext()){
if(lift.match(iterator.next().getDestination())){ }

ConcurrentModificationException In a Java BO

I am getting a java.util.ConcurrentModificationException in this code and can't seem to understand why, or fix it.
In the BO I have this (privileges is an arraylist inside the BO)
public void setPrivilegename(String privilegename) {
this.privileges.add(privilegename);
}
List<PrivilegeObjectBO> arraylist = new ArrayList<PrivilegeObjectBO>();if (rs != null) {
while (rs.next()) {
for (BO bo : arraylist) {
if (bo.getRolepkey()==rs.getInt("ROLE_PKEY")) {
bo.setPrivilegename(rs.getString("SP.NAME"));
}else{
BO newobj = new BO();
newobj.setRolepriviledgepkey(rs.getInt("PRIVILEGE_PKEY"));
newobj.setProticolpkey(protocol);
newobj.setPrivilegename(rs.getString("SP.NAME"));
newobj.setRolepkey(rs.getInt("SRP.ROLE_PKEY"));
arraylist.add(newobj);
}
}
}
}
As per ArrayList javadoc
The iterators returned by this class's iterator and listIterator
methods are fail-fast: if the list is structurally modified at any
time after the iterator is created, in any way except through the
iterator's own remove or add methods, the iterator will throw a
ConcurrentModificationException.
for (BO bo : arraylist)
Above for-each loop gets Iterator for the list and
arraylist.add(newobj);
You are trying to modify the list without using iterators own methods, which results in ConcurrentModificationException
Here is SO discussion on possible solutions.
In java, you will always get a ConcurrentModificationException when you modify the Collection while you are iterating over it.
Possible solution: use a temporary Collection for added or deleted items, and add or delete those items after the iteration is done.
You cannot iterate over ArrayList and add elements to it at the same time with foreach.
Use iterator, like this:
Iterator<PrivilegeObjectBO> iterator = arraylist.iterator();
while (iterator.hasNext()) {
...
}
Others have already pointed out that add-ing to an ArrayList while iterating over it is disallowed.
But to solve your problem anyway, it looks like you need to iterate over the entire list before attempting to add to it, because it your loop appears to be checking to see if anything in the list matches your row to avoid duplicates. In this case you don't want to add to the list while iterating over it because you don't know whether the list has a duplicate until the end.
So just iterate through and check to see if a match is found:
List<PrivilegeObjectBO> arraylist = new ArrayList<PrivilegeObjectBO>();
if (rs != null) {
while (rs.next()) {
boolean found = false;
for (BO bo : arraylist) {
if (bo.getRolepkey() == rs.getInt("ROLE_PKEY")) {
bo.setPrivilegename(rs.getString("SP.NAME"));
found = true;
}
}
if (!found) {
BO newobj = new BO();
newobj.setRolepriviledgepkey(rs.getInt("PRIVILEGE_PKEY"));
newobj.setProticolpkey(protocol);
newobj.setPrivilegename(rs.getString("SP.NAME"));
newobj.setRolepkey(rs.getInt("SRP.ROLE_PKEY"));
arraylist.add(newobj);
}
}
}
Unless you really do want to add a new BO for every non-matching BO already in the list...
Maybe you can take a look at Collections.synchronizedList(List<?>) static method.
It should return a thread safe List from the List object given, and you should not get the exception anymore.
Otherwise, you could try (if applicable) to set the method that accesses to the list synchronized, by adding the keyword synchronized in the method declaration.

Categories

Resources