Java Reference
In-Depth Information
* @return The featured books in this library mapped to their
* (possibly {@code null}) message; never {@code null}.
*/
public Map<Book, String> getFeaturedBooks() {
return this.featuredBooks;
}
}
Functional Iteration
One of the marks of pride in post-functional language communities is that nobody uses a
for
loop anymore.
The abandonment of the
for
keyword has become a minimally acceptable criteria for code, enforced
with righteous zeal. Instead, these languages provide an iterator method. Java 8 joins the ranks of these
post-functional languages with the
forEach
and
forEachRemaining
methods.
The
Iterable
interface now provides a
forEach
method. Some Java developers still don't know about
the
Iterable
interface, which was introduced in Java 5. It is the base class underlying all the Java SDK classes
that can provide an
Iterator
, and it is the class that enabled the enhanced
for
loop introduced in Java 5.
Since the new
forEach
method is on this widely implemented interface, all those implementing classes now
have a
forEach
method, as well.
Semantically, the
forEach
method is the same thing as a
for
loop: it takes a
Consumer
and executes it
for each element in the loop. Practically, however, it's an inside-out
for
loop. Instead of creating a structure
where you iterate over the collection and then execute a series of steps for each iteration, the
forEach
method provides the series of steps to the collection, and the collection applies it to each element in order.
This allows the collection implementation to perform the iteration in the most efficient way possible. Even
better, the code is much more succinct and readable, as Listing 3-2 shows.
Listing 3-2.
Printing out each of the topics using an enhanced for loop and forEach
for (Book book : library.getBooks()) {
System.out.println(book);
}
library.getBooks().forEach(System.out::println);
If you do have some legacy code where you are provided an
Iterator
, however, you can still use a
functional alternative to the loop. In this case, the method is
forEachRemaining
, which applies the lambda
to all the remaining elements of the iterator and exhausts it in the process.
The situation is slightly different for
Map.forEach
. Historically, Java has wanted you to think of a
Map
as
providing access to a
Collection
of
Map.Entry
objects. With Java 8 lambdas, they are breaking away from
that: the
Map.forEach
method does not take a
Consumer
of
Map.Entry
objects, but a rather
BiConsumer
of the
key and value pairs. On the one hand, this makes for reasonably nice-looking inline implementations, such
as in Listing 3-3: there is no more having to call
entry.getKey()
and
entry.getValue()
. On the other hand,
BiConsumer
is an exotic functional type, and very few lambda manipulations or existing method definitions
play nicely with it.
Listing 3-3.
Printing out each of the featured books using the Map version of forEach
library.getFeaturedBooks().forEach(
(book, msg) -> System.out.println(book + ": " + msg)
);