For Each Loop

I realized the other day I often use the old version of the for loop, with collections. Sun has the obligatory explanation that is good if you understand collections and generics. It is here. Their explanation taken verbatim is:


Iterating over a collection is uglier than it needs to be. Consider the
following method, which takes a collection of timer tasks and cancels them:

void cancelAll(Collection c) {
    for (Iterator i = c.iterator(); i.hasNext(); )
    i.next().cancel();
}

 

The iterator is just clutter. Furthermore, it is an opportunity for error. The iterator variable occurs three times in each loop: that istwo chances to get it wrong. The for-each construct gets rid of the clutter and the opportunity for error. Here is how the example lookswith the for-each construct:

 

 

void cancelAll(Collection c) {
    for (TimerTask t : c)
    t.cancel();
}

When you see the colon (:) read it as “in.” The loop above reads as “for each TimerTask t in c.”

What is important here is to read this as follows. Read it as you see the for keyword as "for each" and the colon (:) as "in".
The loop pattern above then becomes, "For each element in array do …".

 

Typed Collections or Generics

Java has had a set of collections which can store any object derived from Object like ArrayList and LinkedList. The problem with this is when storing you basically lost the type of the object and what was retrieved was of type Object. You then were forced to cast to the required type you needed.

NetworkDevice myDevice = (NetworkDevice) devices.get(deviceNumber);

Now we all did it this way and it worked didn't it. But because our ArrayList object accepts anything derived from Object (so any object) you could theorectically add any type, not just of type NetworkDevice.

In Java 5 we now have types collections and

ArrayList myDevices;

 

we can now declare it as

 

private ArrayList myDevices;

 

We have to make a corresponding change where the ArrayList object is created in
the constructor. Instead of:

 

myDevices = new ArrayList();

 

we now write:

 

myDevices = new ArrayList();

This can be read as the <..> roughly as "of". Thus, we can read the new construct "ArrayList" as ArrayList of NetworkDevices". This new definition declares that all elements of this ArrayList will be of type NetworkDevices. The reason for this is javac will enforce this by allowing only NetworkDevices objects to be added.

In a typed collection, since the type of its elements is now known, does not require a cast to be used when objects
are retrieved from it.

If we wanted to iterate over our collection in a method it requires an extra step because it is an untyped Iterator. The solution is to type the Iterator, because a typed collection will then returna typed Iterator:

     // show all out devicespublic void showAllDevices(){
     Iterator nwd = myDevices.iterator();
     while(nwd.hasNext()) {
          NetworkDevices dev = nwd.next();
          System.out.println(dev.toString());    }
     }

     // show all out devicespublic void showAllDevices(){
           Iterator<NetworkDevices> nwd = myDevices.iterator();
           while(nwd.hasNext()) {
               NetworkDevices dev = nwd.next();
               System.out.println(dev.toString());    }
         }

A last note, our collection above used one type parameter. When using a HashMap you do not enter a single element, you enter key/value pairs instead. Like this:

private HashMap<String, String> networkNamesMap;

And there you have it, completely type-safe and elegant.

 

Advertisements