| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Overview of Java 8 additions to Map interface.
Reference: https://www.nurkiewicz.com/2014/04/hashmap-performance-improvements-in.html
Reference: https://dzone.com/articles/java-8-hashmaps-keys-and-the-comparable-interface
Reference: https://yermilov.github.io/blog/2017/02/24/tiebreaker-regarding-java-hashmap-treenode-and-tiebreakorder/
When a bucket exceeds threshold (TREEIFY_THRESHOLD = 8), HashMap dynamically replaces it a tree map. Instead of having pessimistic O(n) we get O(logn). Previously entries with conflicting keys were appended to linked list. Now HashMap uses binary tree (hash code as a branching variable). If two hashes are different but ended up in the same bucket, one is considered bigger and goes to the right. If hashes are equal (as in our case), HashMap hopes that the keys are Comparable, so that it can establish some order. This is not a requirement of HashMap keys, but apparently a good practice.
The tree implementation inside the HashMap is a Red-Black tree, which means it will always be balanced.
When the HashMap implementation tries to find the location of a entry in the tree, first it checks whether the current and the new values are easily comparable (Comparable interface) or not. In the latter case, it has to fall back to a comparison method called tieBreakOrder(Object a, Object b). This method tries to compare the two object based on class name first, and then using System.identityHashCode. However, when the key implements Comparable, the process is much simpler. The key itself defines how it compares to other keys, so the whole insertion/retrieval process speeds up, as there are no extra method calls needed for. It's worth mentioning that the same tieBreakOrder method is used when two Comparable keys turn out to be equal according to the compareTo method (the method returns 0).
In Map.Entry:
default V putIfAbsent(K key, V value)- If the specified key is not already associated with a value (or is mapped to null) associates it with the given value and returns null, else returns the current value.
returns the previous value associated with the specified key, or null if there was no mapping for the key.
Remark: putIfAbsent(1, null) will add an entry (supposing 1 is absent)
default V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) - If the specified key is not already associated with a value (or is mapped to null), attempts to compute its value using the given mapping function and enters it into this map unless null.
returns the current (existing or computed) value associated with the specified key, or null if the computed value is null
Remark: putIfAbsent(1, null) will NOT add an entry (supposing 1 is absent)
putIfAbsent vs computeIfAbsent: stackoverflow differences
default boolean remove(Object key, Object value) - Removes the entry for the specified key only if it is currently mapped to the specified value.
default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) - Replaces each entry's value with the result of invoking the given function on that entry until all entries have been processed or the function throws an exception
Remark: Can't change the element type. To do that - use a stream and collect to the new structure.
default boolean replace(K key, V oldValue, V newValue) - Replaces the entry for the specified key only if currently mapped to the specified value.
default V replace(K key, V value) - Replaces the entry for the specified key only if map contains key.
default V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) - If the value for the specified key is present and non-null, attempts to compute a new mapping given the key and its current mapped value.
If the function returns null, the mapping is removed.
returns the new value associated with the specified key, or null if none
default V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) - Attempts to compute a mapping for the specified key and its current mapped value (or null if there is no current mapping).
If the function returns null, the mapping is removed (or remains absent if initially absent).
returns the new value associated with the specified key, or null if none
default V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) - If the specified key is not already associated with a value or is associated with null, associates it with the given non-null value. Otherwise, replaces the associated value with the results of the given remapping function, or removes if the result is null.
If the function returns null the mapping is removed.
returns the new value associated with the specified key, or null if no value is associated with the key
compute vs merge
We provide tests for above mentioned methods.
stream.sorted(Map.Entry.comparingByKey())
stream.sorted(Map.Entry.comparingByKey((x, y) -> Integer.compare(y, x)))
stream.sorted(Map.Entry.comparingByValue(Comparator.comparingInt(p -> p.getHobbies().size())))
.sorted(Map.Entry.comparingByValue(Comparator.<Person>comparingInt(p -> p.getHobbies().size()).reversed()))
map.forEach((key, value) -> System.out.println(key + ": " + value));
map.getOrDefault(1, "NOT-FOUND");
Map<String, Integer> counter = new HashMap<>();
counter.putIfAbsent("11-u", 0);
map.computeIfAbsent(1, key -> new ArrayList<>()).add("newValue1");
map.remove(key, value)
Map<String, Integer> counter = new HashMap<>(); counter.replaceAll((k, v) -> ++v)
map.replace(1, "oldValue", "newValue");
map.replace(1, "newValue");
map.computeIfPresent(1, (k, v) -> ++v);
map.computeIfPresent(key , (key, set) -> set.remove(valueToRemove) && set.isEmpty() ? null : set);
map.compute(1, (k, v) -> isNull(v) ? 0 : ++v);
map.merge(1, 0, (oldValue, newValue) -> ++oldValue);
| Back | FazBrowse Home | New Git URL |