Simple loop not stopping on String Array - java

Being new to Java, the following code confuses me. I'm trying to do a simple loop based on a list.
List memberships = getMembership(username);
for( Iterator<Integer> single = memberships.iterator(); single.hasNext(); )
{
System.out.println(print_the_current_string_in_list);
}
I have the following questions:
The loop never stops with the above, even though I only have three items in the list. Why is this?
How can I output the current string in the list?

Hopefully your List if of type String and not Integer so it should be
List<String> memberships = getMembership(username);
There are multiple ways to loop over the data for example:
for(String single : memberships) {
System.out.println(single);
}
Another way:
for(int i = 0; i < memberships.size(); i++) {
System.out.println(memberships.get(i));
}
Using the Iterator
for(Iterator<String> iterator = membership.iterator(); iterator.hasNext();) {
System.out.println(iterator.next());
}
Instead of using a for loop you may use an Iterator with a while loop
Iterator<String> iterator = membership.iterator();
while(iterator.hasNext()) {
System.out.println(iterator.next());
}

Try an advanced for loop, like so:
for(String membership : memberships)
System.out.println(membership);

You can use the foreach statement, which uses the iterator that the list has already implemented.
And you should also specify the type of the elements that the list will contain in the List declaration, like this:
List<String> memberships = getMembership(username);
for( String m : memberships )
{
System.out.println(m);
}

You need to actually iterate over the members with next() method from Iterator:
for (Iterator<Integer> single = memberships.iterator (); single.hasNext (); ) {
Integer next = single.next ();
System.out.println (next);
}
Also, you can use the new for each construct:
for (Integer current : memberships)
System.out.println (current);

You haven't iterated through the list.Use next() method.Thats why its going into an infinite loop.
for( Iterator<Integer> single = memberships.iterator(); single.hasNext();{
System.out.println( single.next());
}

Related

How does an Iterator work on a LinkedList? [duplicate]

If I run the following code, it will print out 3 times duplicate, but when I remove the if statement inside the while loop (just to see how many times it will iterate) it starts an infinite loop.
How does actually this hasNext() method working? I thought that will iterate only 5 times as I have 5 items in the list.
public class ExerciseOne {
public static void main(String []args){
String []colors = {"MAGENTA","RED","WHITE","BLUE","CYAN"};
List<String> list = new ArrayList<String>();
for(String color : colors)
list.add(color);
String[] removeColors = {"RED","WHITE","BLUE"};
List<String> removeList = new ArrayList<String>();
for(String color : removeColors)
removeList.add(color);
removeColors(list,removeList);
System.out.printf("%n%nArrayList after calling removeColors:%n");
for(String color : list)
{
System.out.printf("%s ",color);
}
}
private static void removeColors(Collection<String> collection1, Collection<String> collection2)
{
Iterator<String> iterator = collection1.iterator();
while(iterator.hasNext()){
if(collection2.contains(iterator.next()))
System.out.println("duplicate");
}
}
}
It is pretty simple, actually
while(iterator.hasNext()){
if(collection2.contains(iterator.next()))
System.out.println("duplicate");
}
Imagine that the iterator is a pointer to an element of your list.
When you call next(), you're moving this pointer one step ahead.
If you don't move the pointer, hasNext() will always be true because you're still in the beginning of the list.
So you have to call the iterator's next() until there isn't any remaining element in the list.
If you remove the if statement, then it will go for an infinite loop since your iterator.next() is in the if condition. Actually iterator.next() is the api that moves the pointer, not the hasNext(). hasNext() just checks if there is any element in the collection. Since removal of the if statement is also removing the hasNext api, the pointer to the collection is not moving and hasNext is always returning true.
If you take out the iterator.next() from the if condition and move it above the if condition, then the loop will iterate for 5 times even after you remove the if statement.
Iterator<String> iterator = collection1.iterator();
while(iterator.hasNext()){
String currentColor = iterator.next();
if(collection2.contains(currentColor)){
System.out.println("duplicate");
}
}
The question why Iterator is important/introduced is simple:
consider following example:
List<String> list = new ArrayList<String>();
list.add("Anurag");
list.add("Soni");
list.add("MMM");
list.add("GKP");
for(string s : list){
if(s.equals(" Anurag")
s.remove();
System.out.println(s);
}
This will throw an exception-`Concurrent Modification exception` as you are trying to alter the structure of the data structure List before the iteration is completed.
so you may use Iterator for the same purpose .
Iterator iterator = List.iterator();
while(iterator.hasNext()){
String current = iterator.next();
if(current=="Anurag"){
iterator.remove();
}else{
System.out.println(current);
}
}
OUTPUT: Soni
MMM
GKP

enhanced for-loop behavior for handling collection object

As I am learner of Java.. I came across the following code
public static void main(String[] args) {
ArrayList<String> a = new ArrayList<>();
a.add("1");
a.add("2");
for(String str: a){
a = new ArrayList<>();
System.out.println(str);
}
}
I guessed the answer to be
1
null (since the reference is now pointing another object)
but the answer is
1
2
I am unable understand the behavior of enhanced for loop here.
The enhanced for loop creates an Iterator to iterate of the elements of your ArrayList. Changing the a reference to refer to a new ArrayList doesn't affect the Iterator that was created by the loop.
Your loop is equivalent to
Iterator<String> iter = a.iterator();
while (iter.hasNext()) {
String str = iter.next();
a = new ArrayList<>();
System.out.println(str);
}
When you run
for(String str: a)
It gets an iterator from a, then iterates using that iterator. Reassigning a after it has the iterator will have no effect since it isn't using the a reference, it's using the iterator that a returned when the loop started.
This is because, enhanced for loop uses iterator. So changing the reference will not have any impact.
You can check different scenarios here

Iterator not looping

In my project, the user inputs random letters. Then I iterate through my_list to see if any of those random letters appear in my_list. If so, I remove them from my_list.
Example:
List<String> my_list contains: [a, b, c, d]
List<String> rand contains: [r, a]
Goal: The a will be removed from my_list
Problem: The Iterator loops through my_list searching for the letter r. The letter r is not in my_list. But instead of continuing to the next letter a, the iterator exits the loop and the a still remains in my_list
Can someone please tell me why my loop keeps breaking after the first letter?
Here's my code:
public void removeLetters( List<String> my_list, List<String> rand ) {
Iterator<String> i = my_list.iterator();
for( String s : rand ) {
while( i.hasNext() ) {
Object o = i.next();
if( o.toString().equals( s ) ) {
i.remove();
i = my_list.iterator();
break;
}
}
}
}
I hope I explained my problem good enough. Please let me know if I need to explain more in detail.
Thanks
Try creating the Iterator inside the for loop.
for(String s : rand) {
Iterator<String> i = my_list.iterator();
while(i.hasNext()) {
...
}
}
The problem is that in your inner loop you reach the end of i iterator with the first iteration of the outer loop. Then when the second iteration of the for begin, the iterator i hasNext method always return false and it seems that nothing is done, like you said.
You should re initialize your i iterator for each new s of your for
i.remove();
here is your problem. you must remove it from my_list as you explained.
so use
my_list.remove();
You need to reset the Iterator to its beginning before looping through for the next item.
You can only go through an Iterator once. Think about it: once i.hasNext() returns false, you fall out of the inner loop, loop around the outer one, and call i.hasNext() again. Why would it start returning true now?
Bottom line: you have to create a new iterator every time you restart the outer loop (basically move my_list.iterator() call inside the loop)
Better yet, iterate through the list once, and use contains() on the input list:
for(Iterator it = my_list.iterator(); it.hasNext(); ) {
if(rand.contains(it.Next()) {
it.remove();
}
}
If the input list (rand) could be large enough for this to matter, you might want to convert it into a Set before the loop: rand = new HashSet(rand); this will make you algorithm linear rather than quadratic.
Or, just use the one liner:
my_list.removeAll(rand);
You could also use the List's ability to remove objects by equality:
for(String s: rand) {
my_list.remove(s);
}
If you do want to iterate, this is exactly what java.util.AbstractCollection does:
Iterator<String> it = my_list.iterator();
while (it.hasNext()) {
if (rand.contains(it.next())) {
it.remove();
}
}
IS there a reason why you just don't use contains?
public void removeLetters(List<String> my_list, List<String> rand)
{
List<String> updatedList = new ArrayList<String>();
for (String s : my_list)
{
if (!rand.contains(s))
{
updatedList.add(s);
}
}
}

Nested iterating through list followed by an eventual deletion

I'm trying to iterate throuh a list while already looping through it (nested loops). Consider the code below:
ArrayList<Integer> list = new ArrayList<Integer>(); // add some values to it
for(int i : list) { // ConcurrentModificationException
Iterator iterator = list.iterator();
while(iterator.hasNext()) {
int n = iterator.next();
if(n % i == 0) {
iterator.remove();
}
}
}
The example above results in a ConcurrentModificationException. The condition to remove an element is, of course, just an example.
I'm sure I'm just missing something; but how should I construct a loop that achieves the same thing in Java without throwing an exception?
Obviously modifying list when you iterate over it causing the execption.
You can use another list to maintain the list of elements to be removed and remove them at the end.
ArrayList<Integer> list = new ArrayList<Integer>(); // add some values to it
ArrayList<Integer> del = new ArrayList<Integer>(); // Elements to be deleted
for(int i : list) { // ConcurrentModificationException
Iterator iterator = list.iterator();
while(iterator.hasNext()) {
int n = iterator.next();
if(n % i == 0) {
del.add(n);
}
}
}
list.removeALL(del);
Make the outer iteration iterate over a copy of the list.
for (int i : new ArrayList<>(list)) {
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
int n = iterator.next();
if (n % i == 0) {
iterator.remove();
}
}
}
You are getting ConcurrentModificationException because, while doing for loop you are trying to modify the list.
I am not sure whether following is elegant solution or not, but something like below may work:
Iterator<Integer> iterator = list.iterator();
int i=1;
while (iterator.hasNext()) {
int n = iterator.next();
if (n % i == 0) {
iterator.remove();
}
i++;
}
You cannot remove an item from a list that is being iterated. One option is to add the items that you need to another list. Finally you have list with the items you need. Or you can iterate over the clone of your original list.
i do some thing pretty similar to you. hav e alook at this code .
out:for(int h=0; h<tempAl.size(); h++) {
if(tempAl.get(0).split("\\s")[0].equals("OFF")){
tempAl.remove(0);
h=-1;
continue;
}
if(tempAl.get(h).split("\\s")[0].equals("ON")){
ONTime= tempAl.get(h);
///rest fof the code
}
i think you could also change the index after removing element from the arraylist.
I haven't tried, but either use:
List<Integer> list = new ArrayList<Integer>();
// add some values to it
for(Iterator<Integer> iterator1 = list.iterator(); iterator1.hasNext();) {
int i = iterator1.next();
for(Iterator<Integer> iterator2 = list.iterator(); iterator2.hasNext();){
int n = iterator.next();
if(n % i == 0) {
iterator2.remove();
}
}
}
or if this still throws the ConcurrentModificationException (I'm not sure what happens if you use 2 iterators backed by the same list), then use:
List<Integer> list = new ArrayList<Integer>();
// add some values to it
for(int i : new ArrayList(list)){ // copy list
...
}
foreach java syntax hides an iterator but as hiding it, it is not possible to call remove method on this one.
So I would do:
ArrayList<Integer> list = new ArrayList<Integer>(); // add some values to it
int count = 0;
for(Iterator<Integer> it = list.iterator();it.hasNext();count++){ //increments count++
Integer currentInt = it.next();
if(currentInt % count == 0){
it.remove();
}
}
You can see that the same feature is achieved without the need of a secondary iterator.
You can't iterate through the same list in the same time.
To sum up, a modcount variable is used to detect unexpected change of itself everytime a list is parallely changed or iterated over.
Leading thus to a ConcurrentModificationException.
It appears very often with multithreaded environment and developers must be aware of it.
Furthermore, prefer use for loop instead while loop to iterate over a collection.
Why ?
Because with the while way, you let the iterator object still in scope after the loop whereas with for, it doesn't. A simple ackward call to it.next() would end up with a NoSuchElementException.
It is a best practice to keep ;)

Iterator cannot iterative again

Here is my Java code:
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("_name", "name");
map.put("_age", "age");
Set<String> set = map.keySet();
Iterator iterator = set.iterator();
// the first iteration
StringBuffer str1 = new StringBuffer();
while (iterator.hasNext()) {
str1.append(iterator.next() + ",");
}
String str1To = str1.substring(0, str1.lastIndexOf(",")).toString();
System.out.println(str1To);
// the second iteration
StringBuffer str2 = new StringBuffer();
while (iterator.hasNext()) {
str2.append(iterator.next() + ",");
}
String str2To = str2.substring(0, str2.lastIndexOf(",")).toString();// ?????
System.out.println(str2To);
}
My question is,why doesn't the second loop iterate? Does the first iteration already takes the iterator to the end? Is this what affects the second iteration?
How do I fix it?
Your first while loop would move iterate till the iterator reaches the end of the list. At that moment the iterator in itself is pointing to the end of the list, in your case the map.keySet(). And that is the reason why your next while loop fails because the call to the iterator.hasNext() returns false.
A better way would be to use the Enhanced For Loop, something like this instead of your while loops:
for(String key: map.keySet()){
//your logic
}
Iterator's are for one time use only. So ask for iterator again.
You need to call set.iterator() each time you want to iterate through a collection. I suggest that you use a different variable for each iteration as well.

Categories

Resources