I very much want to use Map.computeIfAbsent but it has been too long since lambdas in undergrad.
Then, we apply a groupingBy operation on the string key in order to gather the data for each key together. Note that a simple groupingBy would result in a map from each string key to a list of the corresponding KeyDataPoint triples. We don't want the triples; we want DataPoint instances, which are (timestamp, data) pairs.
Almost directly from the docs: it gives an example of the old way to do things:
And the new way:
But in their example, I think I’m not quite “getting it.” How would I transform the code to use the new lambda way of expressing this?
Answers:
Suppose you have the following code:
Then you will see the message
creating a value for 'snoop'
exactly once as on the second invocation of computeIfAbsent
there is already a value for that key. The k
in the lambda expression k -> f(k)
is just a placeolder (parameter) for the key which the map will pass to your lambda for computing the value. So in the example the key is passed to the function invocation.Alternatively you could write:
whoLetDogsOut.computeIfAbsent('snoop', k -> k.isEmpty());
to achieve the same result without a helper method (but you won’t see the debugging output then). And even simpler, as it is a simple delegation to an existing method you could write: whoLetDogsOut.computeIfAbsent('snoop', String::isEmpty);
This delegation does not need any parameters to be written.To be closer to the example in your question, you could write it as
whoLetDogsOut.computeIfAbsent('snoop', key -> tryToLetOut(key));
(it doesn’t matter whether you name the parameter k
or key
). Or write it as whoLetDogsOut.computeIfAbsent('snoop', MyClass::tryToLetOut);
if tryToLetOut
is static
or whoLetDogsOut.computeIfAbsent('snoop', this::tryToLetOut);
if tryToLetOut
is an instance method.Answers:
Recently I was playing with this method too. I wrote a memoized algorithm to calcualte Fibonacci numbers which could serve as another illustration on how to use the method.
We can start by defining a map and putting the values in it for the base cases, namely,
fibonnaci(0)
and fibonacci(1)
:And for the inductive step all we have to do is redefine our Fibonacci function as follows:
As you can see, the method
computeIfAbsent
will use the provided lambda expression to calculate the Fibonacci number when the number is not present in the map. This represents a significant improvement over the traditional, tree recursive algorithm.Answers:
Another example. When building a complex map of maps, the computeIfAbsent() method is a replacement for map’s get() method. Through chaining of computeIfAbsent() calls together, missing containers are constructed on-the-fly by provided lambda expressions:
Answers:
This is really helpful if you want to create a Multimap without using guava library (https://google.github.io/guava/releases/19.0/api/docs/com/google/common/collect/Multimap.html)
For eg: If you want to store a list of students who enrolled for a particular subject.
The normal solution for this using jdk library is
The normal solution for this using jdk library is
Since it have some boiler plate code, people tend to use guava Mutltimap.
Using Map.computeIfAbsent, we can write in a single line without guava Multimap as follows.
Stuart Marks & Brian Goetz did a good talk about this
https://www.youtube.com/watch?v=9uTVXxJjuco
https://www.youtube.com/watch?v=9uTVXxJjuco
Answers:
There is no difference between using computeIfAbsent() and simple put() get()
functions of a map. In other words you can rewrite your function in this way
functions of a map. In other words you can rewrite your function in this way
Tags: function
Hash table based implementation of the Map
interface. This implementation provides all of the optional map operations, and permits null
values and the null
key. (The HashMap
class is roughly equivalent to Hashtable
, except that it is unsynchronized and permits nulls.) This class makes no guarantees as to the order of the map; in particular, it does not guarantee that the order will remain constant over time. This implementation provides constant-time performance for the basic operations (
get
and put
), assuming the hash function disperses the elements properly among the buckets. Iteration over collection views requires time proportional to the 'capacity' of the HashMap
instance (the number of buckets) plus its size (the number of key-value mappings). Thus, it's very important not to set the initial capacity too high (or the load factor too low) if iteration performance is important. An instance of
HashMap
has two parameters that affect its performance: initial capacity and load factor. The capacity is the number of buckets in the hash table, and the initial capacity is simply the capacity at the time the hash table is created. The load factor is a measure of how full the hash table is allowed to get before its capacity is automatically increased. When the number of entries in the hash table exceeds the product of the load factor and the current capacity, the hash table is rehashed (that is, internal data structures are rebuilt) so that the hash table has approximately twice the number of buckets. As a general rule, the default load factor (.75) offers a good tradeoff between time and space costs. Higher values decrease the space overhead but increase the lookup cost (reflected in most of the operations of the
HashMap
class, including get
and put
). The expected number of entries in the map and its load factor should be taken into account when setting its initial capacity, so as to minimize the number of rehash operations. If the initial capacity is greater than the maximum number of entries divided by the load factor, no rehash operations will ever occur. If many mappings are to be stored in a
HashMap
instance, creating it with a sufficiently large capacity will allow the mappings to be stored more efficiently than letting it perform automatic rehashing as needed to grow the table. Note that using many keys with the same hashCode()
is a sure way to slow down performance of any hash table. To ameliorate impact, when keys are Comparable
, this class may use comparison order among keys to help break ties. Note that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the map. If no such object exists, the map should be 'wrapped' using the
Collections.synchronizedMap
method. This is best done at creation time, to prevent accidental unsynchronized access to the map: The iterators returned by all of this class's 'collection view methods' are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own
remove
method, the iterator will throw a ConcurrentModificationException
. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future. Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw
ConcurrentModificationException
on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.Java Can Computeifabsent Generate Multiple Key Entries For Beginners
This class is a member of the Java Collections Framework.