What is a For Each loop?
A For Each loop is a way of iterating over a collection or data structure. The benefit of using the For Each loop instead of your typical For loop is that we have access to the objects in the collection.
A for each loop is declared as
for (type variable : collection) { statements; }
As you can see, we don't need to increase a counter each time we go through the loop, nor do we need to check that the index is in range. This is all done for us. A quick example:
// Array with 5 elements, 1-5
int[] array = {1, 2, 3, 4, 5};
// Print each element in the array to console
for (int i : array) {
System.out.println(i);
}
This would output:
1
2
3
4
5
Now, this doesn't seem like a massive thing - and it's not, really. It does makes things easier to do though. Now, we can also use the for each loop to iterate over other collections, such as HashMaps. This is slightly more complicated.
Editing Elements
One of the limitations of the For Each loop is that you are unable to edit elements within a Collection. An example to demonstrate this:
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
// Create a new ArrayList and add some elements to it
ArrayList<String> names = new ArrayList<String>();
names.add("Steve");
names.add("Joe");
names.add("Bob");
// Go through and change each String s in names, then print to console
for (String s : names) {
s += " After Edited";
System.out.println(s);
}
// Print each String s in names to console
for (String s : names) {
System.out.println(s);
}
}
}
Now you may expect the above code to output the same in each foreach loop. The actual output is:
Steve After Edited
Joe After Edited
Bob After Edited
Steve
Joe
Bob
Changing the variable in the foreach loop will not change it in the collection. It is a copy, and so anything you do with it will not be edited outside of the loop. So we can edit the variable, although maybe not with the results that we'd expect. What about editing the collection? Let's try replacing
for (String s : names) {
s += " After Edited";
System.out.println(s);
}
with
for (String s : names) {
names.remove(s);
System.out.println(s);
}
Now, think about what would happen if this were legal. We would remove String s from names, but String s is actually a copy - so we can still access it and edit it as we wish. Obviously, this could lead to some unintended and possibly surprising behaviour. So this will throw an exception - specifically, a ConcurrentModificationException. The output:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
at java.util.AbstractList$Itr.next(Unknown Source)
at Main.main(Main.java:12)
It's telling you that you can't modify the collection while it is already being accessed. If you would like to edit the elements a collection has, you can use an Iterator to do so:
import java.util.ArrayList;
import java.util.Iterator;
public class Main {
public static void main(String[] args) {
// Create an ArrayList and add some elements
ArrayList<String> names = new ArrayList<String>();
names.add("Steve");
names.add("Joe");
names.add("Bob");
// Create an Iterator. Notice that we instantiate by called iterator() on the collection
Iterator<String> iter = names.iterator();
// Remove each elemenet in the collection. Notice that we use iterator.remove.
while (iter.hasNext()) {
iter.next(); // Get the next element. Will throw IllegalStateException otherwise
iter.remove();
}
// Print the ArrayList to the console
System.out.println(names);
}
}
The output will be:
[]
HashMaps and For Each Loops
// Map.Entry is what we will be using to iterate over the HashMap
import java.util.Map.Entry;
import java.util.HashMap;
public class Main {
// Declaring our HashMap - we have to use Integer instead of int here. Same as
// Double, Float, etc.
// String - name, Integer - age
private static HashMap<String, Integer> people;
public static void main(String[] args) {
// Instantiate our HashMap and add some entries.
people = new HashMap<String, Integer>();
people.put("John Doe", 35);
people.put("Jane Doe", 27);
people.put("Bobby", 24);
// Go through and print the Name and Age of each person.
for (Entry<String, Integer> entry : people.entrySet()) {
System.out.println("Name: " + entry.getKey());
System.out.println("Age: " + entry.getValue());
}
}
}
Now, to explain the for each loop.
for (Entry<String, Integer> entry : people.entrySet()) {
Quite a lot is happening here. First, Entry<String, Integer> entry is creating a Map Entry variable - entry. A Map Entry is a way of accessing elements from an Entry Set, and will hold a Key and Value.
Next, we get use people.entrySet() to get a Set of the collection. We use this to iterate over. Anything that we do with the entry set also happens to the HashMap, so if we remove an element, it is removed from both.
System.out.println("Name: " + entry.getKey());
System.out.println("Age: " + entry.getValue());
Here we access the Key and Value of the entry - fairly straight forward.
The output of the above code. Notice how it isn't sorted, or in the order you put them in due to how HashMaps work.
Name: John Doe
Age: 35
Name: Bobby
Age: 24
Name: Jane Doe
Age: 27
Implementing For Each for Our Own Classes
import java.util.Iterator;
// Create a new collection that implements Iterable
public class NewCollection<E> implements Iterable<E> {
public Iterator<E> iterator() {
// Implement code to iterate collection here
// Outside the scope of this tutorial
}
}
public class Main {
public static void main(String[] args) {
// Create an instance of our new collection
MyCollection<String> collection = new MyCollection<String>();
// Code to insert stuff in our collection
// Using For Each loop with our collection. Easy!
for (String s : collection) {
System.out.println(s);
}
}
}
It's relatively simple to allow the use of For Each on our own collections - we just have to implement Iterable.
And that's For Each loops!







MultiQuote


|