how hasnext() works in collection in java - java

program:
public class SortedSet1 {
public static void main(String[] args) {
List ac= new ArrayList();
c.add(ac);
ac.add(0,"hai");
ac.add(1,"hw");
ac.add(2,"ai");
ac.add(3,"hi");
ac.add("hai");
Collections.sort(ac);
Iterator it=ac.iterator();
k=0;
while(it.hasNext()) {
System.out.println(""+ac.get(k));
k++;
}
}
}
output:
ai
hai
hi
hw
hai
how it execute 5 times??
while come to hai no next element present so condition false. But how it executed.

Your loop above iterates through the list using an index. it.hasNext() returns true until it reaches the end of the list. Since you don't call it.next() within your loop to advance the iterator, it.hasNext() keeps returning true, and your loop rolls on. Until, that is, k gets to be 5, at which point an IndexOutOfBoundsException is thrown, which exits the loop.
The proper idiom using an iterator would be
while(it.hasNext()){
System.out.println(it.next());
}
or using an index
for(int k=0; k<ac.size(); k++) {
System.out.println(ac.get(k));
}
However since Java5, the preferred way is using the foreach loop (and generics):
List<String> ac= new ArrayList<String>();
...
for(String elem : ac){
System.out.println(elem);
}

the point is ac.get(k) doesn't consume any element of the iterator at the contrary of it.next()

That loop will never terminate. it.hasNext does not advance the iterator. You have to call it.next() to advance it. The loop probably terminates because k becomes 5 at which point the Arraylist with throw a bounds exception.
The correct form of iterating a list (containing strings) is either:
Iterator it = ac.iterator();
while (it.hasNext) {
System.out.println((String) it.next());
}
Or if the list is typed, e.g. ArrayList
for (String s : ac) {
System.out.println((String) s);
}
Or if you absolutely know this is an array list and need speed over terseness:
for (int i = 0; i < ac.size(); i++) {
System.out.println(ac.get(i));
}

Related

Why do I get a ConcurrentModificationException?

Why do I get a ConcurrentModificationException at the specified location in my code? I cannot figure out what I am doing wrong... The removeMin() method is being used to locate the min in the list pq, remove it, and return its value
import java.util.Iterator;
import java.util.LinkedList;
public class test1 {
static LinkedList<Integer> list = new LinkedList<Integer>();
public static void main(String[] args) {
list.add(10);
list.add(4);
list.add(12);
list.add(3);
list.add(7);
System.out.println(removeMin());
}
public static Integer removeMin() {
LinkedList<Integer> pq = new LinkedList<Integer>();
Iterator<Integer> itPQ = pq.iterator();
// Put contents of list into pq
for (int i = 0; i < list.size(); i++) {
pq.add(list.removeFirst());
}
int min = Integer.MAX_VALUE;
int pos = 0;
int remPos = 0;
while (itPQ.hasNext()) {
Integer element = itPQ.next(); // I get ConcurrentModificationException here
if (element < min) {
min = element;
remPos = pos;
}
pos++;
}
pq.remove(remPos);
return remPos;
}
}
An Iterator should not be considered usable once the Collection from which it was obtained is modified. (This restriction is relaxed for java.util.concurrent.* collection classes.)
You are first obtaining an Iterator for pq, then modifying pq. Once you modify pq, the Iterator itPQ is no longer valid, so when you try to use it, you get a ConcurrentModificationException.
One solution is to move Iterator<Integer> itPQ = pq.iterator(); to right before the while loop. A better approach is to do away with the explicit use of Iterator altogether:
for (Integer element : pq) {
Technically, the for-each loop uses an Iterator internally, so either way, this loop would only be valid as long as you don’t try to modify pq inside the loop.
I ran your code, and it turns out that the offending line is here:
Iterator<Integer> itPQ = pq.iterator();
This needs to come after your population of pq, so that the iterator does not have it's data updated asynchronously.
With this modification the code runs.
Now, it does not run correctly. The reason is as #Ishnark pointed out in his answer, that every time you are removing from the list, it gets smaller, and so not all of the list is being added to pq.
You face an issue because you added items to pq, using the normal .add() method after you had already created an Iterator for pq. The Iterator doesn't complain when you do the hasNext() because it sees the change in pq.
while (itPQ.hasNext()) {
...
Integer element = itPQ.next(); --> you get exception here
...
}
However, it throws an exception when you attempt to iterate through pq. According to this post, "If the iterator detects that some modifications were made without using its method (or using another iterator on the same collection), it cannot guarantee anymore that it will not pass twice on the same element or skip one, so it throws this exception."

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

Why isn't my program removing "all"?

My problem is, when I output this code, it's not outputting what I want which is to remove the "all". It outputs the same exact thing the first print statement did.
Here's my code:
// RemoveAll
// Spec: To remove the "all"
// ArrayList remove() exercise
import java.util.ArrayList;
public class RemoveAll
{
public static void main(String args[])
{
ArrayList<String> ray;
ray = new ArrayList<String>();
int spot = ray.size() - 1;
ray.add("all");
ray.add("all");
ray.add("fun");
ray.add("dog");
ray.add("bat");
ray.add("cat");
ray.add("all");
ray.add("dog");
ray.add("all");
ray.add("all");
System.out.println(ray);
System.out.println(ray.size());
// add in a loop to remove all occurrences of all
while (spot >= 0)
{
if (ray.get(spot).equalsIgnoreCase("all"))
{
ray.remove(spot);
}
spot = spot - 1;
}
System.out.println("\n" + ray);
System.out.println(ray.size());
}
}
Any ideas?
you are determining size() before filling list
put this after once you have list filled (i.e. after all add())
int spot = ray.size() - 1;
Another way to remove items from the list is to use an Iterator:
for(Iterator<String> i = ray.iterator(); i.hasNext(); ) {
if(i.next().equalsIgnoreCase("all")) {
i.remove();
}
}
That way you don't have to keep track of where you are in the list with respect to removed items.
Two problems. You are setting the size of spot before the array has any values in it so it will have a value of -1 when you get to
while (spot >= 0)
also you are mutating (modifying) the array while you are iterating over it which will cause all sorts of errors. The way you want to do this is using an iterator
Iterator iter = ray.iterator();
while(iter.hasNext()){
String cur = iter.next();
//logic to determin if you need to remove
iter.remove();
}

How to make a list iterator that starts at the end of the list

I have a homework question that asks me to make a list iterator that starts at the end of the list. I have no idea how to do this. Here is the code
public class LinkedListTester7
{
public static void main(String [] args)
{
LinkedList<Integer> list = new LinkedList<Integer>();
for (int i = 0 ; i < 100 ; i = i + 2)
list.add(i) ;
//-----------Start below here. To do: approximate lines of code = 3
// 1. make a list iterator that starts at the end of the list ;
ListIterator<Integer> litr = list.listIterator();
//2. while hasPrevious ;
while (litr.hasPrevious()) {
//3. print what is returned by previous() followed by a blank without a newline
System.out.println(litr.previous()+ " ");
}
//-----------------End here. Please do not remove this comment. Reminder: no changes outside the todo regions.
System.out.println() ;
}
}
Read the java.util.List API documentation...
ListIterator<Integer> litr = list.listIterator(list.size());
Aactually a A ListIterator has no current element; its cursor position always lies between the element that would be returned by a call to previous() and the element that would be returned by a call to next().
If you want the first call to next()/previous() to return the last element you could use listIterator(int index) and pass it list.size() -1 if you want to iterate forward or list.size() if you want to iterate backward.
I think this might be the code you're looking for:
for (int i = litr.size(); i >= 0; i--) {
System.out.println(litr.get(i));
}
Basically it starts at the end of the array and prints the results from last to first.
This is what's starting at the END of the ArrayList:
i = litr.size();
i-- counts backwards through the array until it reaches 0.

Java - Collection.remove() behaves differently in different conditions

This is a follow up to my previous question :
Collection - Iterator.remove() vs Collection.remove()
The below two pieces of code , which apparently differs only by a single line , but one throws exception and other don't . Can you please explain the difference ?
List<String> list = new ArrayList<String>
(Arrays.asList("noob1","noob2","noob3"));
System.out.println(list);
for (String str : list) {
if (str.equals("noob2")) {
list.remove(str);
}
}
runs fine , but if i change the condition to
if (!str.equals("noob2"))
the code throws exception !
What happens in this situation is you are removing the second list element.
List<String> list = new ArrayList<String>
(Arrays.asList("noob1", "noob2", "noob3", "noob4"));
System.out.println(list);
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
String str = iterator.next();
if (str.equals("noob3")) {
System.out.println("Checking "+str);
list.remove(str);
}
}
System.out.println(list);
prints
[noob1, noob2, noob3, noob4]
Checking noob1
Checking noob2
Checking noob3
[noob1, noob2, noob4]
By removing the second last element you have reduced the size to the number of elements which you have iterated over.
// from ArrayList.Itr
public boolean hasNext() {
return cursor != size;
}
This causes the loop to exit early before the concurrent modifcation check is performed in next(). If you remove any other element next() is called and you get a CME.
BTW Something which also bypasses the check is
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
String str = iterator.next();
System.out.println("Checking "+str);
if (str.equals("noob2")) {
list.remove("noob1");
list.remove("noob3");
}
}
as long as the size of the collection is the same as the index it is up to, the check is not performed.
The for loop is just a simplified syntax for an iterator scan of the list. The iterator may throw an exception if the list is modified under it, but it is not guaranteed. Because of hasNext, iterators are often working one element ahead, making the first case less likely to be affected by list modification. By the time "noob2" is removed, the iterator already knows about "noob3".
Actually you should never remove collections' elements during "casual" iterating. When you have to modify your collection in some loop you have to use iterator to make these operations.
public class Test {
public static void main(String... args) {
List<String> list = new ArrayList<String>(Arrays.asList("noob1", "noob2", "noob3"));
System.out.println(list);
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String str = iterator.next();
if (!str.equals("noob2")) {
iterator.remove();
}
}
System.out.println(list);
}
}
I suppose the exception is thown because you are trying to change a collection you are looping on... and not because the if condition.
I suggest you to create a new list only containing the items that verify the condition. Add them to the new list and avoid to change the original collection.
It's because you are trying to remove from a Collection you are currently iterating through. Making a minor alteration you can do what you want to do:
String[] strValues = {"noob1","noob2","noob3"}; // <<< Array
List<String> list = new ArrayList<String>(Arrays.asList(strValues));
System.out.println(list);
for (String str : strValues) { // << List is duplicate of array so can iterate through array
if (!str.equals("noob2")) {
list.remove(str);
}
}
That should work. Hopefully
Well, your first case doesn't throw the Exception because, the iterator returns false for Iterator.hasNext() at index 2 as you remove the element at index 1.
Iterator<String> itr = list.iterator();
while(itr.hasNext()){
String s= itr.next();
if(s.equals("noob2")){
list.remove(s); // size of the list is 2 here
System.out.println(itr.hasNext());// this returns false as it doesn't have anything at index 2 now.(on 2nd iteration )
}
}
You can test it clearly using a simple for-loop:
for (int i=0; i<list.size(); i++) {
if (list.get(i).equals("noob2")) {
System.out.println(list.get(i));
System.out.println(list.size());
list.remove(list.get(i));
System.out.println(list.size());
}
}
Output:
[noob1, noob2, noob3]
noob2
3
2
Notice the size of the list after you remove the element, which fails after incrementing. 2<2 which is false

Categories