Java Reference
In-Depth Information
This code is really four lines to accomplish a single piece of logic: get the value for the key, setting
the value if it is missing. Aside from being lengthy, this code is also unclear; it's not clear that value is still
effectively in the process of being generated after the get . Even more, this code is inefficient: it does a get
followed by a put, requiring a duplicate lookup of the key.
Instead, the Map class now provides you with a way to access the map and implement this special
handling in a single method call, which ensures that the returned value is fully configured when you receive
it and saves you the overhead of the repeated lookup. This is a perfect case of how lambdas let developers
write code that is more efficient and more expressive and safer - all at the same time.
The most common use case that I have encountered is for defaulted values. For instance, let's create
a method that will get the featured book message, providing the default value if it is not set. We'll follow
the same default message created in Listing 3-7, but provide the default value on key lookup. We will
do this using the computeIfAbsent method, which is the easy way of calculating defaults. Note that the
computeIfAbsent method is also a convenient way to implement multimaps or canonicalized mappings,
which are simply special cases of defaulted values.
map.computeIfAbsent(key, k -> new HashMap<>()); // Multimap
map.computeIfAbsent(key, Function.identity()); // Canonicalized mapping
Listing 3-7. A Library instance method to provide featured book messages using Map.computeIfAbsent
* Provides a featured book message for the given book. If the topic was not
* previously a featured book, it will be after this method resolves. If it
* did not previously have a featured book message, it will have one after
* this method resolves.
* @param featuredBook The topic whose message is desired; never {@code null}
* @return The message for the featured book; never {@code null}
public String getFeaturedBookMessage(Book featuredBook) {
Objects.requireNonNull(featuredBook, "featured book");
return this.getFeaturedBooks().computeIfAbsent(featuredBook, book ->
"Featured " + book.getGenre().toString().toLowerCase() + " book by "
+ book.getAuthor()
Another common task with maps is to keep track of instance counts. For instance, consider if we wanted
to generate genre counts for certain user-specified genres. For this, we can specify computeIfPresent . This
method is the complement to computeIfAbsent : it only executes its lambda if the value already exists. This
functionality is very useful for updating certain existing values without creating additional values in the map.
To provide these genre counts, we will first initialize the desired keys to zero, and then we will iterate over
all the topics, incrementing the count if it already exists. We do this in Listing 3-8. The computeIfPresent
method is also useful for providing any kind of initialization or wrapping code on the values of the method
while sidestepping the null check.
Search WWH ::

Custom Search