For 2 days I'm pretty confused about .hasNext(); and next(); methods of Iteration interface especially in while loop. Let me give an example:
import java.util.*; // imported whole java.util package.
class Main {
public static void main(String[] args) {
ArrayList<String> cars = new ArrayList<String>(); // created ArrayList which name is cars.
cars.add("Volvo");
cars.add("Mercedes");
cars.add("BMW");
Iterator<String> x = cars.iterator();
while(x.hasNext()) {
System.out.print(x.next() + " "); // It prints Volvo Mercedes BMW
}
}
}
I understood that .hasNext(); is boolean and it returns true if iteration has elements. The .next(); method returns the next element. After first element Volvo, it gets back while(x.hasNext()) and entering the inside of loop again but where is the counter of this loop? I mean after printing Volvo how can it goes to the next element? It returns all element and if there is no more .hasNext(); returns false and code continues to next line is simple answer and correct but I want to understand it clearly.
Actually the iterator() Method Creates an iterator for all elements in your (let's say) Arraylist. Now in Your Code, the condition of while loop x.hasNext() checks whether the list contains an element or not, if yes it will return true else false.
Now x.next() point to First Element (Like of LinkedLists for example) in Your ArrayList and store that Object(Volvo in your case). When You Call this method it basically gives you reference of that object in List and the Iterator Moves to next element in the List. When Calling next() method the iterator(x in your case) returns the object and then moves to next Element (Mercedes in your case).
Now When you call next() method Again you will find Mercedes is returned. To know How it Works type System.out.println(x.next()) thrice instead of while loop u will understand that it moves to next location. If you type System.out.println(x.next()) fourth time it will give exception because there is no element in your list furthur more. Exception in thread "main" java.util.NoSuchElementException This is the Exception.
That's why hasNext() method is used as it checks whether an element is there or not.
you can Compare this to printing of linkedlist(Data structure if you know) where we make one object point to head node print it and move to next node. Same Case is here it returns current element(object) and moves to next element(object).
while is java-ese for: Keep doing this until a thing changes.
It's a bit like this common household task:
How to wash dishes
Check if there are still dirty dishes on the right side of the counter.
If there are some, do the dishwash thing: Pick up the nearest dirty dish, and wash it, then stow it away on the left side of the counter, and go back to the start of this algorithm.
Otherwise (there are no dirty dishes), you are done.
while (counterRightSide.hasItems()) {
Dish dirty = counterRightSide.fetch();
Dish clean = sink.clean(dirty);
counterLeftSide.stow(clean);
}
EDIT: I realize now that 'a kitchen counter' is an unfortunate example, given the homonym 'kitchen counter' and 'counter in code'. I'll use 'accumulator' instead of 'counter in code' to fix this confusion.
Note how there is no accumulator here either, and you aren't counting in your head when you wash the dishes either. You COULD first take inventory of the amount of dirty dishes you have (say, 15 dishes), and then write a protocol where you grab a dirty dish exactly 15 times before decreeing that you've done the job, but surely you realize that that's just one way to do it, and another is to just... check if there are any dirty dishes left every time you're done washing 1 dirty dish. Which is how the above code works.
Note that the action of 'fetching' an item from the right side of the kitchen counter changes properties of that kitchen counter. It now has one less item on it.
The same applies to iterators: Calling .next() on an iterator changes it in some form. After all, if you call next twice, the results of these calls are different. Contrast with invoking, say, someArrayList.get(5) a bunch of times in a row; that doesn't change the arraylist at all, and therefore you get the same thing back every time. next() is not like that.
So how DOES that work? Who counts this stuff?
Well, that's the neat thing about abstraction! A 'Collection' is something that can do a few things, such as 'it must be able to report to how how many items it holds', and, 'it must be able to festoon you an object that can be used to loop through each item that it holds'.
That's what an iterator is: An object that can do that.
So how does it work? Who knows! It doesn't matter! As long as you CAN do these things, you can be a collection, you are free to implement the task however you like.
Okay, but how does a common collection, like, say, ArrayList do this?
With a counter, of course. Here's the implementation:
public Iterator<T> iterator() {
return new Iterator<T>() {
int counter = 0; // here it is!
public boolean hasNext() {
return counter < size();
}
public int next() {
return get(counter++);
}
};
}
you're getting this object and referencing it in your code (your x variable), and that object has a field with a counter in it. You can't see it; it's private, and not actually in the Iterator type (Iterator is an interface; what you get is some unknown subtype of it, and that contains the counter variable). That's assuming you're getting an iterator by invoking .iterator() on an arraylist. If you invoke it on something else, there may or may not be a counter - as long as the iterator WORKS, it doesn't matter how it works, that's the beauty of interfaces.
A while loop checks the condition and when condition is true then executes the body of the loop and iterates itself,
while(condition){
//do something.
}
The hasNext() is a method from the Iterator interface which returns true if the "iteration" has more elements, if there are no more elements it returns fals and will no longer enter the body of the while loop:
while(x.hasNext){
//do something.
}
The next() method is a method from the Iterator interface and returns the next element of the iteration.
while(x.hasNext){
x.next();
}
I mean after printing Volvo how can it goes to the next element? It
returns all element and if there is no more .hasNext(); returns false
and code continues to next line is simple answer and correct but I
want to understand it clearly.
int cursor; // index of next element to return
//...
public boolean hasNext() {
return cursor != size;
}
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];
}
//...
Given above is how ArrayList#hasNext and and ArrayList#next have been implemented. The code is straight forward and easy to understand. You can check the full code by using a decompiler or here.
Related
I want to know about iterator design pattern and found on following tutorial.
http://www.journaldev.com/1716/iterator-design-pattern-in-java-example-tutorial
Following is the code for hasNext() and next() methods.
#Override
public boolean hasNext() {
while (position < channels.size()) {
Channel c = channels.get(position);
if (c.getTYPE().equals(type) || type.equals(ChannelTypeEnum.ALL)) {
return true;
} else
position++;
}
return false;
}
#Override
public Channel next() {
Channel c = channels.get(position);
position++;
return c;
}
and using above method collection iterated is
while (baseIterator.hasNext()) {
Channel c = baseIterator.next();
System.out.println(c.toString());
}
If we are using hasNext() and next() methods it look like we are using while loop twice.
is this ok when application is small enough and performance is the priority? or there can be optimized code?
The performance of Iterator depends on its implementation. Every Java collection has its own iterator implementation, so the performance will vary. Usually hasNext and next methods have no loops. The code you are showing is some special iterator from the tutorial which iterates while performing the filtering. While you have two nested loops, you actually traverse the underlying collection channels only once as position constantly increases from 0 to channels.size(). The hasNext() internal loop is necessary to skip the unwanted items, but it does not add the computational difficulty. The overall difficulty of such iteration is O(channels.size()).
Note that this iterator implementation breaks the Iterator interface contract. First it does not throw NoSuchElementException at the end of the iteration. Second, if you call next() several times without calling hasNext() you will have different results. Thus I would not recommend use the samples from this tutorial in the real code.
what do you mean by "using while loop twice" ? if you are concerned whether you iterate twice over the collection, then it doesn't seem so to me. the iterator keeps a position pointer that in both methods only seems to go forward. so while you do have nested loops (one in the application code, on in hasNext() method) they do not fetch the same item
Collections
If channels are some kind of Iterable, then you can write the loop as
for(Channel c : channels) {
if(c.getTYPE().equals(type)
|| type.equals(ChannelTypeEnum.ALL)) {
return true;
}
}
return false;
No need to increment position if you're using that position only for iteration to the next element.
This is only shorthand - code for using an iterator as stated in comments - so it will not gain much in terms of performance but adds clarity to your code. Implementing your own iterator as you did in code above is not neccessary if the type of your channels already is a Collection and implements Iterable
This is the fastest way to iterate over a Set:
int size = mySet.size();
Iterator<Integer> iteration = mySet.iterator();
for(int j = 0; j < size; j ++){
doSomethingWith(iteration.next());
}
In this loop, you avoid the call to iteration.hasNext() with every step, which is why it is faster than the traditional iterator loop, and faster than the enhanced for-loop.
Of course, differences are very small, and you should optimize like this only if performance is really very important for your code.
This question already has answers here:
Calling next on an Iterator once vs multiple times
(3 answers)
Closed 7 years ago.
I had some trouble with the whole iterator concept and for a question in one of my quizzes, I honestly couldn't understand what was up.
public static void main(String[] args)
{
Deque<String> SQ1 = new ArrayDeque<String>();
SQ1.add("Give");
SQ1.add("Me");
SQ1.add("The");
SQ1.add("Best");
SQ1.add("Of");
SQ1.add("Both");
SQ1.add("Worlds");
Iterator<String> It = SQ1.iterator();
while(It.hasNext())
{
if(It.next().equals("Give"))
System.out.print(It.next());
}
}
This is the code, and the question is what will be the output. The correct answer is "Me" when I thought it was "Give". I don't understand how the whole run goes.
This is what I understand:
It does have a next. If that next equals "Give", it will print out that next value. In this case, that value should be "Give", shouldn't it?
Could someone please help me understand this?
The if-statement calls It.next() to check the value, and the the print statement calls It.next() again, rather than printing the value that you just checked.
So what you see will always be the element directly after "Give".
The correct answer is "Me" when I thought it was "Give". I don't understand how the whole run goes.
Right, the code is illustrating a common error. The error is that the code is telling the iterator to advance to the next item and give it to us twice:
Iterator<String> It = SQ1.iterator();
while(It.hasNext())
{
if(It.next().equals("Give"))
// here^^^^^^^^^
System.out.print(It.next());
// and here -------------^^^^^^^^^
}
So it's getting the value, seeing if it's "Give", and then if that value was "Give" it throws it away and gets the next value, which in your test data is "Me". (Note that if "Give" were the last entry, that second call to next would throw an error, since there would be no next entry at that point.)
To "fix" it and have it show "Give", still using that kind of loop, you'd remember the result of the call in a variable, and then use the variable in those two places:
Iterator<String> It = SQ1.iterator();
while(It.hasNext())
{
String value = It.next();
if(value.equals("Give"))
System.out.print(value);
}
But, this is what the enhanced for loop is for: You don't use an It variable at all, just:
for (String value : SQ1) {
if(value.equals("Give"))
System.out.print(value);
}
As you can see from the Java docs:
next
E next()
Returns the next element in the iteration.
Returns:
the next element in the iteration
Throws:
NoSuchElementException - if the iteration has no more elements
So your call:
If(It.next().equals("Give"))
Actually returns the "next" value and sets the Iterator 'It' to the next one in your ArrayDeque.
If you call next again you will be one step further.
We all know that the safest "and probably only safe" way of removing an object from a collection while iterating it, is by first retrieving the Iterator, perform a loop and remove when needed;
Iterator iter=Collection.iterator();
while(iter.hasNext()){
Object o=iter.next()
if(o.equals(what i'm looking for)){
iter.remove();
}
}
What I would like to understand, and unfortunately haven't found a deep technical explanation about, is how this removal is performed,
If:
for(Object o:myCollection().getObjects()){
if(o.equals(what i'm looking for)){
myCollection.remove(o);
}
}
Will throw a ConcurrentModificationException, what does "in technical terms" Iterator.remove() do? Does it removes the object, breaks the loop and restart the loop?
I see in the official documentation:
"Removes the current element. Throws IllegalStateException if an
attempt is made to call remove() that is not preceded by a call to
next( )."
The part "removes the current element", makes me think of the exact same situation happening in a "regular" loop => (perform equality test and remove if needed), but why is the Iterator loop ConcurrentModification-safe?
The reason why you cannot modify a list while iterating over it is because the iterator has to know what to return for hasNext() and next().
How this is done is implementation specific, but you could have a look at the source code of ArrayList/AbstractList/LinkedList etc.
Also note that in some situations you can use some code like this as an alternative:
List<Foo> copyList = new ArrayList<>(origList);
for (Foo foo : copyList){
if (condition){
origList.remove(foo);
}
}
But this code will probably run slightly slower because the collection has to be copied (shallow copy only) and the element to remove has to be searched.
Also note that if you're using the iterator directly it's recommended to use a for loop instead of while loop as this limits the scope of the variable:
for (Iterator<Foo> iterator = myCollection.iterator(); iterator.hasNext();){
...
}
How exactly Iterator removes elements depends on its implementation, which may be different for different Collections. Definitely it doesn't break the loop you're in. I've just looked how ArrayList iterator is implemented and here's the code:
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
So it checks for concurrent modifications, removes element using public ArrayList remove method, and increments counter of list modifications so ConcurrentModificationException won't be thrown at next iteration.
Short introduction:
I'm building a game, where monsters spawn at the top, and moves through a path, to the reach a point where they need to be removed/destroyed/deleted. But I can't seem to get the Monster Object deleted.
for (Monster i : Monstre)
{
this.add(i); //adds monster to JPanel
if(i.monstery > 50 && i.monsterx > 50){ //check if monster have reached end point
this.remove(i); //Should remove Object from the JPanel ?
i = null; //Sets object too null
Monstre.remove(i); //Removes object from arrayList "Monstre".
}else{
//Update the monsters bounds
The above removes the object from the JPanel, and it seems to be all good. But when i call System.out.println(Monstre.size()); I get an increasing amount of monsters spawned, and if increasing the monster spawn rate, the program starts to eventually slow down, because amount of monsters in the Monstre arraylist is over 9000, and never decreasing.
What I'm looking for, is a way to remove these objects while the game is running.
Remove the i = null; line. This is not C and you don't have to assign your variables to null. JVM will do that for you (google "java garbage collection"). Because of that line, you practically call Monstre.remove(null) which does not work.
Also, you cannot iterate over the collection in that manner and modify it (remove values). Save the monsters you want to delete in an array outside of the scope of the loop, and remove them after the loop finishes. Otherwise, use an iterator:
Iterator<Monster> it= Monstre.iterator();
while (it.hasNext()) {
Monster i= it.next();
//code code code
if (shouldDelete) {
this.remove(i);
it.remove();
}
}
In addition to the suggestion in the first answer, you should change your loop. Removing items from the Monstre list while using the for-each loop will cause problems.
Instead try :
Iterator<Monster> iter = Monstre.iterator ();
while (iter.hasNext())
{
i = iter.next();
this.add(i); //adds monster to JPanel
if(i.monstery > 50 && i.monsterx > 50){ //check if monster have reached end point
this.remove(i);
iter.remove();
}else{
EDIT :
Here's an explanation where you can't use the for-each loop :
So when should you use the for-each loop? Any time you can. It really
beautifies your code. Unfortunately, you cannot use it everywhere.
Consider, for example, the expurgate method. The program needs access
to the iterator in order to remove the current element. The for-each
loop hides the iterator, so you cannot call remove. Therefore, the
for-each loop is not usable for filtering. Similarly it is not usable
for loops where you need to replace elements in a list or array as you
traverse it. Finally, it is not usable for loops that must iterate
over multiple collections in parallel. These shortcomings were known
by the designers, who made a conscious decision to go with a clean,
simple construct that would cover the great majority of cases.
i = null; //Sets object too null
Monstre.remove(i); //Removes object from arrayList "Monstre".
Here you set the variable i to null then you request that i (i.e. null) is removed from your arraylist, the arraylist does not contain null so nothing happens. Setting things equal to null is very rarely nessissary.
As you have correctly said removing the i=null upsets the program, this is because you are iterating through the list and then changing the list while iterating, you have two options;
1) go through the Arraylist in a manor similar to an array
import java.util.*;
public class Test{
public static void main(String [] args){
ArrayList<Double> doubles=new ArrayList<Double>();
for(double i=0;i<10;i++){
doubles.add(i);
}
//remove 7.0s from doubles
for(int i=doubles.size()-1;i>=0;i--){
//must go through backwards - see http://stackoverflow.com/questions/12111210/java-arraylist-search-and-remove for why
if (doubles.get(i).equals(7.0)){
doubles.remove(i);
}
}
}
}
2) use an iterator and its remove method
import java.util.*;
public class Test{
public static void main(String [] args){
ArrayList<Double> doubles=new ArrayList<Double>();
for(double i=0;i<10;i++){
doubles.add(i);
}
//remove 7.0s from doubles
Iterator<Double> iterator=doubles.iterator();
while(iterator.hasNext()){
Double testDouble=iterator.next();
if (testDouble.equals(7.0)){
iterator.remove();
}
}
}
}
You cannot remove this element in a for-loop.
You need to use listIterator() method to retrieve an iterator that can be modified and loop with iterator-style. Otherwise you would always get java.util.ConcurrentModificationException
The following is isEmpty() method from ConcurrentWeakKeyHashMap.java,
https://github.com/netty/netty/blob/master/src/main/java/org/jboss/netty/util/internal/ConcurrentWeakKeyHashMap.java
Why does it need mcsum, and what does the if(mcsum!= 0) {..} block doing ?
And more importantly, how do I get
if (segments[i].count != 0 || mc[i] != segments[i].modCount)
to evaluate to true?
public boolean isEmpty() {
final Segment<K, V>[] segments = this.segments;
/*
* We keep track of per-segment modCounts to avoid ABA problems in which
* an element in one segment was added and in another removed during
* traversal, in which case the table was never actually empty at any
* point. Note the similar use of modCounts in the size() and
* containsValue() methods, which are the only other methods also
* susceptible to ABA problems.
*/
int[] mc = new int[segments.length];
int mcsum = 0;
for (int i = 0; i < segments.length; ++ i) {
if (segments[i].count != 0) {
return false;
} else {
mcsum += mc[i] = segments[i].modCount;
}
}
// If mcsum happens to be zero, then we know we got a snapshot before
// any modifications at all were made. This is probably common enough
// to bother tracking.
if (mcsum != 0) {
for (int i = 0; i < segments.length; ++ i) {
if (segments[i].count != 0 || mc[i] != segments[i].modCount) {
return false;
}
}
}
return true;
}
EDIT:
Code to evaluate the above if block is now in ConcurrentWeakKeyHashMapTest
Essentially 1 thread continously monitors the concurrentMap, while another thread continuously add/remove same keypair value
This method is a copy of the same in Javas ConcurrentHashMap.
This kind of Map is using a modCount per segment to track during operations if it remained unchanged by different treads. During our traversal of the Map there could actually be other operations modifying the Map. This is called an ABA problem. We are asking the Map if it is empty and in fact it is not, but by accident it appears to be. A simple example:
Map with three segements
Segment 1: size=0
Segment 2: size=0
Segment 3: size=1
In this moment we decide to ask the Map and look into segment 1, which appears to be empty.
Now another algorithm comes and inserts an element to segment 1, but removes the other from segment 3. The Map was never empty.
Our Thread is running now again and we look into segment 2 and 3, both are empty. For us the Map is empty - as a result.
But for any empty slot we tracked whether it was modified, too. And for slot 3 we realize there have been modifications: mc[2]>=1 which means mcsum>=1. This means: since construction the Map was modified at least once. So to answer what mcsum is for: It is a shortcut for the default empty ConcurrentHashMap. If there never have been modifications, we do not need to check for concurrent modifications.
So we know something happened and check again each segment. If now a segment is empty we know what its modCount has been. For segment 3, lets say it was 1, for segment 1 it has been 0. Checking the modCount of segment 1 now it is 1 and the count is > 0 so we know that the Map is not empty.
Still there could be an ABA problem in the second loop as well. But because we know the modCounts we can catch any other concurrent algorithm changing something. So we say if the segment is empty and something changed with the modCount it has not been empty in the first place. That is, what the second loop is doing.
Hope this helps.
EDIT
And more importantly, how do I get
if (segments[i].count != 0 || mc[i] != segments[i].modCount)
to evaluate to true?
This evaluates to true if a segment contains something or if something was modified since the first loop. And it evaluates to false (which means: segment empty) if the segment contains nothing AND nothing was changed since the first loop. Or, to say it differently: We can be sure it has been empty all the time since looked on the checked segment first.
The mcsum checks if the map has ever been structurally modified. There appears to be no way to reset the modification counts to zero, so if the map has ever contained anything at all mcsum will be non-zero.
The weak keys are only cleaned up when the map is changed through a put, remove, et c, and they are only cleaned up within the modified segment. Retrieving values from the map does not clear up the weak keys. This means the map as implemented will hold many weak keys that have been garbage collected as they are only cleaned up if the same segment is modified.
This means results from the size() and isEmpty() methods will frequently return the wrong result.
With the API as provided your best recourse is to call purgeStaleEntries() prior to checking if the map is empty.