Iterator Confused [duplicate] - java

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.

Related

Usage of Iteration's .hasNext(); and .next(); methods in Java

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.

Can I store the returned object from Iterator.next() method?

I have read that Iterator .next() method returns the object, but I get an error saying it is not a statement. I am pretty new to Java, so help would be very appreciated!
I have tried with both Iterator, Iterator and ListIterator. I get the same error. My code is for homework and is pretty long, so I will just add what I think is most relevant here. Please ask if you need to see more!
Iterator<Person> itr = work.iterator();
while (itr.hasNext()){
Person this = itr.next();
if (this.birthday == time){
if (once == 0){
System.out.println("Birthday: "+time);
once++;
}
work.remove(this);
As you can see I am using the stored object multiple times, so I don't think I can use itr.next() several times as it will move to the next value.
My error:
Homework4.java:145: error: not a statement
Person this = itr.next();

Searching through a collection of an array list pair [duplicate]

This question already has answers here:
How to compare two java objects [duplicate]
(5 answers)
Closed 9 years ago.
I am trying to search through a collection of an ArrayList if pairs. What I want to be able to do, is to go through the collection and find the first value in a pair and return the second value of that pair. The problem I am having is that the check I have to find the first value doesn't seem to be working, so every time I search, I end up returning null. I know that the problem exists with my if statement, but I cannot seem to sort out what it is I am doing wrong. Since this is a homework assignment, I can't show all the code to my pair class, or my pair list class, but I can show you the method I have for searching the first value:
public S findFirst(F firstValue) {
Iterator<Pair> myIter = this.iterator();
S tmp2 = null;
while (myIter.hasNext()) {
Pair tmp1 = myIter.next();
if (tmp1.getFirst() == firstCall) {
tmp2 = (S) tmp1.getSecond();
}
}
return tmp2;
}
If I throw in an else statement that just calls what I am attempting to do in my if check, like this:
else{
tmp2 = (S) tmp1.getSecond();
}
then whenever I test for the first value, I get the second value, so I know I am at least on the correct path, but I am assuming that I am doing something wrong with what I am checking for in my if statement. Does anyone know how I can correctly do this, (and please bear in mind that this is homework, so a guide to how to figure this out is far more valuable to me than just some random answer, I want to learn, not just be given an answer) Thanks in advance!
Don't use == to compare objects. Override and use equals().
I think
if (tmp1.getFirst() == firstCall)
should probably say
if (tmp1.getFirst().equals(firstValue))
The important difference is that == checks whether two expressions refer to the exact same object. You're more interested in knowing whether your two expressions actually refer to objects that are equal.
Try this:
if (tmp1.getFirst().equals(firstValue))
instead of
if (tmp1.getFirst() == firstCall)
Also you can override your own equals method.
You should never use == to compare objects.
Check How to compare two java objects
What Matt says, (don't use == ) but I think a bigger problem is that you don't return the 'first' encounter.... your if statement should look like:
public S findFirst(F firstValue) {
Iterator<Pair> myIter = this.iterator();
while (myIter.hasNext()) {
Pair tmp1 = myIter.next();
if (firstValue.equals(tmp1.getFirst())) {
return (S) tmp1.getSecond();
}
}
return null;
}

how to resolve java.util.NoSuchElementException

I first had the following code
with the following error message
java.util.ConcurrentModificationException
java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(HashMap.java:894)
at java.util.HashMap$KeyIterator.next(HashMap.java:928)
at ca.on.oicr.pinery.lims.gsle.GsleClient.getOrders(GsleClient.java:720)
Where line 720 is the second for loop.
I got the answer that I am adding to orders inside a loop that's looping over the elements of orders, that's what causes the exception. Don't modify a collection you're looping over inside the loop. Likewise with samples.
So I re-did this method but I get the following error message:
java.util.NoSuchElementException
java.util.NoSuchElementException
at java.util.ArrayList$Itr.next(ArrayList.java:794)
at ca.on.oicr.pinery.lims.gsle.GsleClient.getOrders(GsleClient.java:730)
Where line 730 is Set samples = sampleOrderMap.get(it.next().getId()) in my following code
How would I fix this error message, and will this new method have the same functionality of my original method that did not work, I feel that having all these loops and conditional statements will cause it to not work.
In the following code fragement:
while (it.hasNext()) {
if (sampleOrderMap.containsKey((it.next().getId()))) { // calling it.next()
if (it.next().getId() != null) { // again calling it.next() ?
Set<OrderSample> samples = sampleOrderMap.get(it.next().getId()); //again calling
for (OrderSample orderSample : samples) {
Set<Attribute> attributes = attributeOrderMap.get(orderSample.getId());
////............ your code
You are consecutively calling it.next() upon each call of iterator.next(), the iterator advances by one element by returning it. Though i am not sure what object it.next() is returning, but you can assign it to a Object of the collection type and use it inside the while loop as follows:
while (it.hasNext()) {
Order order = (Order)it.next(); // if Order is your list's type
if (sampleOrderMap.containsKey((order.getId()))) {
if (order.getId() != null) {
Set<OrderSample> samples = sampleOrderMap.get(order.getId());
for (OrderSample orderSample : samples) {
Set<Attribute> attributes = attributeOrderMap.get(orderSample.getId());
I'm assuming it is an Iterator. (I say that because you did not post the entire source code needed to reproduce this, which you should really do in the future.)
So each time you call it.next() you are advancing that iterator. You are calling it.next() three times in the first four lines. So if there's only one item left in the Iterator, the initial call to it.hasNext() will return true but you'll only be able to call it.next() once more before running out of items.
while (it.hasNext()) {
OrderSample nextSample = it.next();
// blah blah blah
// use nextSample instead of it.next() in each subsequence instance.
}

Java is not assigning values to my variables correctly, with linked lists

public void returnRental(Customer cust){
Rental toDelete = null; //Rental to be removed from list.
LinkedList<Video> toReturn = null; //List of videos to be added to inventory.
//Find appropriate rental according to customer name.
for(int i = 0; i < rentals.size(); i++){
if(cust.getName() == rentals.get(i).getRentee().getName()){
toReturn = rentals.get(i).getRented();
toDelete = rentals.get(i);
}
}
here is the snippet of code that is giving me problems. I've debugged it in eclipse quite a bit which ended up just confusing me more. It hits the if, and passes the condition. But once it gets to assigning values to "toReturn" it assigns it an empty list with size 0. Where as I check my rentals Linked list and the correct value are there, but for some reason it is not getting assigned to my variables correctly :( The same happens to "toDelete" but this isn't a list, it is one instance of my class Rental. (The linked list is a list of rentals, which contains a linked list of videos)
No errors are thrown...
Its a little difficult to explain, if you need more information please let me know and i'll clarify.
I'm at a loss, possibly because I'm not iterating through my linked list correctly?
Replace
if (cust.getName() == rentals.get(i).getRentee().getName()){
by
if (cust.getName().equals(rentals.get(i).getRentee().getName())){
You can't compare strings with == (except if your algorithm can ensure this is the same instance, which is almost never the case).
But the missing equals is not the only bug. It may be inside getRented() or elsewhere (you don't show what you do with toReturn and toDelete, so it's not clear if you don't have problems here).
Now, to go on chasing your bugs, you should either
debug, and put a breakpoint in your loop to check the state of rentals.get(i) and the execution at this point
if you can't debug, put a lot of System.println, so that you know what you have...
I've upvoted dystroy's answer because incorrect string comparison is always wrong.
But because that would fail differently (customer names not matching rentee names), I'm wondering if your issue is really caused by either of the following:
a problem in getRented(); or
cust having a null name on call, which would match a Rentee with a null name.
Possibly, your if condition is being hit more than once. First of all, check if this is actually happening. If so, check your logic and determine if you want to stop at the first occurence or at the last (this case seems to be the latter).
If you want to stop at the first occurence, break the iteration:
for(int i = 0; i < rentals.size(); i++){
if(cust.getName() == rentals.get(i).getRentee().getName()){
toReturn = rentals.get(i).getRented();
toDelete = rentals.get(i);
break;
}
}
for(int i = 0; i < rentals.size(); i++){
if(cust.getName().equals( rentals.get(i).getRentee().getName())){
toReturn.addAll(rentals.get(i).getRented());
//assumming it returns the list of Video object
toDelete = rentals.get(i);
}
}

Categories