Monday, July 26, 2021

Enhance For Loop Example and Puzzle in Java

From Java 5 onwards, we have a for-each loop for iterating over collection and array in Java. For each loop allows you to traverse over collection without keeping track of index like traditional for loop, or calling hasNext() method in while loop using Iterator or ListIterator. For-each loop indeed simplified iteration over any Collection or array in Java, but not every Java programmer is aware of some useful details of the for-each loop, which we will see in this tutorial. Unlike other popular items from Java 5 release alias Generics, Autoboxing, and variable arguments, Java developers tend to use for-each loop more often than any other feature, but when asked about how does advanced foreach loop works or what is a basic requirement of using a Collection in the for-each loop, not everyone can answer.

This small tutorial and example aim to bridge that gap by going through some interesting foreach loop puzzles. So, without any further delay let's see our first puzzle on Java 5 for each loop.


Advanced for loop Puzzle 1

Consider below code of Iterating over a user-defined aggregator or collection class in Java, what does it will print or will it throw any exception or compile-time error :

package test;

/**
  * Java Class to show how for-each loop works in Java
  */
public class ForEachTest {  
   
    public static void main(String args[]){
        CustomCollection<String> myCollection = new CustomCollection<String>();
        myCollection.add("Java");
        myCollection.add("Scala");
        myCollection.add("Groovy");
       
        // What does this code will do, print language, throw exception
        // or compile time error
        for(String language: myCollection){
            System.out.println(language);
        }
    }
}



and here is our CustomCollection class, It's parametric generic class, similar to any other Collection class, backed by ArrayList and provides methods to add and remove items from Collection.

package test;

public class CustomCollection<T>{
    private ArrayList<T> bucket;
   
    public CustomCollection(){
        bucket = new ArrayList();
    }

    public int size() {
        return bucket.size();
    }

    public boolean isEmpty() {
        return bucket.isEmpty();
    }

    public boolean contains(T o) {
        return bucket.contains(o);
    }
   
    public boolean add(T e) {
        return bucket.add(e);
    }

   
    public boolean remove(T o) {
        return bucket.remove(o);
    }   
   
}

Answer : 
Advanced for loop Puzzle and Example in Java
Above code will fail to compile because our CustomCollection class doesn't implement java.lang.Iterable interface, as shown in below compile time error :

Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - for-each not applicable to expression type

  required: array or java.lang.Iterable
  found:    test.CustomCollection
        at test.ForEachTest.main(ForEachTest.java:24)

Interesting fact to know is that for-each loop is applicable only to Java array and Collection classes which implements Iterable interface, and since all built-in Collection classes implements java.util.Collection interface, which already extends Iterable, this detail mostly gets unnoticed. You can see it in type declaration of Collection interface public interface Collection extends Iterable. So in order to fix above issue, you can either simply make CustomCollection implements Collection interface or extends AbstractCollection, which is default general purpose implementation and shows how to use abstract class and interface together for better flexibility. Now let's see second puzzle about for-each loop in Java.

Second For-Each Puzzle in Java

In following code example, which block of code will throw ConcurrentModificatoinException in Java. Here we are iterating over ArrayList using standard iterator and for-each loop and subsequently removing elements as well, you need to find out which code will throw ConcurrentModificationException and why? remember answer could be both, none or any one of them, so beware.

package test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/**
  * Java class to demonstrate inner working of for-each loop in Java
  * @author Javin Paul
  **/
public class ForEachTest2 {  
   
    public static void main(String args[]){
        Collection<String> list = new ArrayList<String>();
        list.add("Android");
        list.add("iPhone");
        list.add("Windows Mobile");
       
        // Which Code will throw ConcurrentModificationException, both, 
        // none or one of them
       
        // example 1        
        Iterator<String> itr = list.iterator();
        while(itr.hasNext()){
            String lang = itr.next();
            list.remove(lang);
        }
       
         // example 2
        for(String language: list){
            list.remove(language);
        }
    }
}

About 70% Java developers will say that first code block will throw ConcurrentModificatoinException because we are not using Iterator's remove method for removing elements, instead we are using ArrayList's remove() method. But, not many Java developer will say same thing about for-each loop, because we are not using Iterator there. 

In reality, the second code snippet will also throw ConcurrentModificationException, which is quite obvious after solving first puzzle. Since for-each loop internally uses Iterator to traverse over Collection, it also calls Iterator.next(), which checks for modification and throws ConcurrentModificationException

You can see this from the following output, which you will get, when you run second code snippet after commenting on the first one :

Exception in thread "main" java.util.ConcurrentModificationException
        at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
        at java.util.AbstractList$Itr.next(AbstractList.java:343)
        at test.ForEachTest2.main(ForEachTest2.java:34)

That's all on this post about Java 5 for-each loop guys. We have seen, couple of common mistake Java programmers make, while writing traversing code for Collection class, especially  removing element, while iterating over collection. Remember always use Iterator's remove method for deleting objects from any Collection e.g. Map, Set or List and keep in mind that for-each loop is just a syntactic sugar over standard Iterator code idiom.


1 comment :

Anonymous said...

Actually for each loop or advance for loop of Java 5 is nothing but a wrapper around iterator, e.g. following code :

for(String s : listOfString){
System.out.println(s)
}

is nothing but equal to

for(Iterator it = listOfString.iterator(); it.hashNext(); ){
String s = it.next();
Systme.out.println(s);
}

for each loop though has a limitation e.g. you cannot call remove() mehtod of Iterator because no refernece is available, it's mearely inferred.

You can also use for each with array and any class which impelments Iterable interface in Java.

Post a Comment