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

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

Related

Java Iterator going in infinite while loop

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.

How "remove" function works for ArrayList while iterating using for-each loop?

I have a very basic question.
I have created simple ArrayList and I am removing the item while iterating using for-each loop. It gives me java.util.ConcurrentModificationException because I can't remove an item while iterating but when I un-comment the if condition it works fine.
Please can anybody explain me how for-each works in this way.
ArrayList<String> list1 = new ArrayList<String>();
list1.add("Hello");
list1.add("World");
list1.add("Good Evening");
for (String s : list1) {
//if (s.equals("World")) {
list1.remove(1);
//}
}
If I change it to list1.remove(2); or list1.remove(0); then also its working fine.
Note: This is sample code and I know it will work fine using Iterator. My sole purpose of this question is to know how method remove() works perfectly if condition is un-commented no matter what index you are removing from the list.
The list has a variable called modCount, which means "modification count". Whenever you call remove (or perform other structural modifications), it increments the modCount.
The iterator can't keep track of its position in the list if you are adding or removing elements without telling the iterator. So as a safety check, at the start of iteration, the iterator makes a note of the modCount, saving it as expectedModCount. When each item is read from the iterator, the iterator checks to make sure the modCount still equals the expected value, and throws an exception if it doesn't.
Usually, this will successfully cause the exception to be thrown if the list is unsafely modified during iteration. However, it's not sufficient in this case when the if statement is enabled. After your code has read "World", that item is removed, and so the list now contains ["Hello", Good Evening"]. The iterator is still at position 1 (which now contains "Good Evening") and when it tries to read the next item, it finds it has now reached the end of the list, so it doesn't bother to check the modCount. Hence, no exception.
Note the caveat in the ConcurrentModificationException documentation: "It is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throw ConcurrentModificationException on a best-effort basis."
Even if it doesn't happen to throw the exception in this case, the code is still wrong. To remove an element while iterating, you must use the iterator's own remove method:
for (Iterator<String> it = list1.iterator(); it.hasNext();) {
String s = it.next();
if (s.equals("World")) {
it.remove();
}
}
That way, the iterator knows that the list has changed and can still iterate correctly.
Alternatively, you can iterate from a temporary copy of the list:
for (String s : new ArrayList<>(list1)) {
if (s.equals("World")) {
list1.remove(...);
}
}
Although, in this simple case, you don't even need to do that; you can just write:
list1.remove("World");
You can also use an index-based removal. The drawback of this solution is that the list1.size() gets evaluated during every loop iteration. The positive thing is that removing an item from a List by its index is faster.
for (int i = 0; i < list1.size(); /* i incremented in loop body */) {
if ("World".equals(list1.get(i))) {
list1.remove(i);
}
else {
i++;
}
}
Use an Iterator and call remove():
Iterator<String> iter = list1.iterator();
while (iter.hasNext()) {
String str = iter.next();
if (someCondition)
iter.remove();
}

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.

How to iterate over a SortedSet to modify items within

lets say I have an List. There is no problem to modify list's item in for loop:
for (int i = 0; i < list.size(); i++) { list.get(i).setId(i); }
But I have a SortedSet instead of list. How can I do the same with it?
Thank you
First of all, Set assumes that its elements are immutable (actually, mutable elements are permitted, but they must adhere to a very specific contract, which I doubt your class does).
This means that generally you can't modify a set element in-place like you're doing with the list.
The two basic operations that a Set supports are the addition and removal of elements. A modification can be thought of as a removal of the old element followed by the addition of the new one:
You can take care of the removals while you're iterating, by using Iterator.remove();
You could accumulate the additions in a separate container and call Set.addAll() at the end.
You cannot modify set's key, because it causes the set rehasing/reordering. So, it will be undefined behaviour how the iteration will run further.
You could remove elements using iterator.remove(). But you cannot add elements, usually better solution is to accumulate them in a new collection and addAll it after the iteration.
Set mySet = ...;
ArrayList newElems = new ArrayList();
for(final Iterator it = mySet.iterator(); it.hasNext(); )
{
Object elem = it.next();
if(...)
newElems.add(...);
else if(...)
it.remove();
...
}
mySet.addAll(newElems);
Since Java 1.6, you're able to use a NavigableSet.
You should use an Iterator or better still the enhanced for-loop syntax (which depends on the class implementing the Iterable interface), irrespective of the Collection you're using. This abstracts away the mechanism used to traverse the collection and allows a new implementation to be substituted in without affecting the iteration routine.
For example:
Set<Foo> set = ...
// Enhanced for-loop syntax
for (Foo foo : set) {
// ...
}
// Iterator approach
Iterator it = set.iterator();
while (it.hasNext()) {
Foo foo = it.next();
}
EDIT
Kan makes a good point regarding modifying the item's key. Assuming that your class's equals() and hashCode() methods are based solely on the "id" attribute (which you're changing) the safest approach would be to explicitly remove these from the Set as you iterate and add them to an "output" Set; e.g.
SortedSet<Foo> input = ...
SortedSet<Foo> output = new TreeSet<Foo>();
Iterator<Foo> it = input.iterator();
while (it.hasNext()) {
Foo foo = it.next();
it.remove(); // Remove from input set before updating ID.
foo.setId(1);
output.add(foo); // Add to output set.
}
You cannot do that. But you may try, maybe you'll succeed, maybe you'll get ConcurrentModificationException. It's very important to remember, that modifying elements while iterating may have unexpected results. You should instead collect that elements in some collection. And after the iteration modify them one by one.
This will only work, if id is not used for equals, or the comperator you used for the sorted set:
int counter = 0;
for(ElementFoo e : set) {
e.setId(counter);
couter++;
}

Performance difference between Iterator Class and foreach construct

I have the following code running, but I sometimes get some sort of concurrency exception when running it.
ArrayList<Mob> carriers = new ArrayList<Mob>();
ArrayList<Mob> mobs = new ArrayList<Mob>();
...
for (Mob carrier : carriers){
for (Mob mob : mobs){
checkInfections (carrier, mob);
}
}
I refactored it to solve the concurrency problem, but it did lead me to a question. Would there be a difference in performance if I change the for construct to an Iterator pattern? What's the access level difference between the foreach construct and the Iterator class?
The difference is largely syntactic sugar except that an Iterator can remove items from the Collection it is iterating. Technically, enhanced for loops allow you to loop over anything that's Iterable, which at a minimum includes both Collections and arrays.
Don't worry about performance differences. Such micro-optimization is an irrelevant distraction. If you need to remove items as you go, use an Iterator. Otherwise for loops tend to be used more just because they're more readable ie:
for (String s : stringList) { ... }
vs:
for (Iterator<String> iter = stringList.iterator(); iter.hasNext(); ) {
String s = iter.next();
...
}
Behind the scenes the new style for is implemented in terms of iterators by the compiler, so there will be no difference if you do that yourself.
The "some sort of concurrency exception" you're talking about is most likely java.util.ConcurrentModificationException. You get this because you cannot change the list while you are iterating over it; if you do that, the iterator will notice and throw this exception.
If you need to remove elements from a list while iterating over it, then do it through the remove() method on the iterator, for example:
List<String> list = ...; // wherever you get this
for (Iterator<String> iter = list.iterator(); iter.hasNext(); ) {
String s = iter.next();
if (...) {
iter.remove(); // Remove element through iterator
}
}
(Note: You can't use the foreach syntax for the loop in this case, because you need explicit access to the iterator).
You can use Iterator(interface) only on collections like List, Set & Queue but for each loop cab be used for everything which is iterable like Collections and Array. And for each loop is more readable..

Categories

Resources