With Lambda expressions support in Java 8, programmers now have a new, concise and interesting way for iterating over a collection - the so-called internal iteration. So what does it differ from the normal (external) iteration method? Let’s see some examples.

Here’s a classic example of collection iteration which we’ve been seeing and using for years:

List<String> fruits = Arrays.asList("apple", "banana", "lemon", "orange");

for (String aFruit : fruits) {
	System.out.println(aFruit);
}
Doing this way, we take each element out of the collection for iterating from the first to the end. Thus it is called “external iteration”.

We know that in Java, all the collection interfaces (List, Set, Queue, etc) have the Iterable as their super interface. And since Java 8, the Iterable interface introduces a new method:

void forEach(Consumer<? super T> action)

According to its Javadoc, this method “Performs the given action on the contents of the Iterable, in the order elements occur when iterating, until all elements have been processed or the action throws an exception.” - That means we can use this method for iterating over a collection, and perform the given action on each element, by passing a “behavior” - a class that implements the Consumer interface. The Javadoc also states that, internally, implementation of the forEach() method should iterate over its elements in the following fashion:

for (T t : thisList)
	action.accept(t);
With that in mind, the previous example can be re-written as follows:

fruits.forEach(new Consumer<String>() {
	public void accept(String s) {
		System.out.println(s);
	}
});
Here, we create an anonymous inner class which is passed into the forEach() method. Obviously, this anonymous class must implement the Consumer interface and override its accept() method.

Now, because the Consumer is a functional interface with the functional method accept(), we can replace the code of the anonymous class above with a Lambda expression like this:

fruits.forEach(s -> System.out.println(s));
Here, the Lambda expression is an anonymous representation of a function descriptor of a functional interface. Interestingly, we can use static method reference to make the code even more concise:

fruits.forEach(System.out::println);


How can this be possible? Well, with implementation of closures in Java, the compiler sees that the signature of the referenced method happens to match the erased function descriptor of the Consumer interface, so it will generate an appropriate anonymous class whose functional method calls the referenced method. With that in mind, suppose that we have the following class:

class Fruit {
	static void countWord(String s) {
		System.out.println(s.length());
	}
}
Now, we know that it’s legal to pass a static method reference to the forEach() method like this:

fruits.forEach(Fruit::countWord);
Using the forEach() method as in the above examples is referred as “internal iteration” - not because the way of iteration is different than the iteration method using “classic enhanced for loop”. It’s called internal iteration because the collection does the iteration itself, instead of having the external code takes every element out of the collection. And more importantly, the forEach() method allows us to use Lambda expressions and method reference syntax to pass in the action would be performed for each element in the collection. That makes our code more concise, more dynamic and functional.

For your convenient, we assemble all the code snippets presented above into a sample program so that you can run and experiment yourself with the concepts. Here’s the code:

package net.codejava.lambda;

import java.util.*;
import java.util.function.*;

public class LambdaIterationExample {

	public static void main(String[] args) {
		List<String> fruits = Arrays.asList("apple", "banana", "lemon", "orange");

		System.out.println("==== Classic enhanced for loop ====");

		for (String aFruit : fruits) {
			System.out.println(aFruit);
		}


		System.out.println("\n==== Anonymous class ====");

		fruits.forEach(new Consumer<String>() {
			public void accept(String s) {
				System.out.println(s);
			}
		});


		System.out.println("\n==== Lambda Expression ====");

		fruits.forEach(s -> System.out.println(s));


		System.out.println("\n==== Lambda Method Reference ====");

		fruits.forEach(System.out::println);


		System.out.println("\n==== Lambda Method Reference 2 ====");

		fruits.forEach(Fruit::countWord);
	}

}

class Fruit {
	static void countWord(String s) {
		System.out.println(s.length());
	}
}
Output of the program:

==== Classic enhanced for loop ====
apple
banana
lemon
orange

==== Anonymous class ====
apple
banana
lemon
orange

==== Lambda Expression ====
apple
banana
lemon
orange

==== Lambda Method Reference ====
apple
banana
lemon
orange

==== Lambda Method Reference 2 ====
5
6
5
6
 

API References

 

Other Java Collections Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Attachments:
Download this file (LambdaIterationExample.zip)LambdaIterationExample.zip[Java source file]4 kB

Add comment