Hashmap Implementation in java, Map interface Exemples

Hashmap Implementation in java, Map interface Exemples

Java Hashmap Implementation introduced several default methods supported by the Map interface. (Default methods are covered in detail here “Java Collections Tutorial” , but here you can think of them as being Java Hashmap Implementation methods in an interface.) The purpose of these new operations is to help you write more concise code by using a readily available idiomatic pattern instead of implementing it yourself. We look at these operations in the following sections, starting with the shiny new forEach.

Iterate Hashmap In Java

forEach java iterator example:

Iterating over the keys and values of a Map has traditionally been awkward. In fact, you
needed to use an Hashmap java iterator of a Map.Entry<K, V> over the entry set of a Map:

for(Map.Entry<String, Integer> entry: ageOfFriends.entrySet()) {
String friend = entry.getKey();
Integer age = entry.getValue();
System.out.println(friend + " is " + age + " years old");
}

Since Java 8, the Map interface has supported the java forEach method, which accepts a BiConsumer, taking the key and value as arguments. Using java forEach makes your code more concise:

ageOfFriends.forEach((friend, age) -> System.out.println(friend + " is " +
age + " years old"));

Java Sort Hashmap

A concern related to Iterate Hashmap In Java over date is Java Sort Hashmap. Java 8 introduced a couple of convenient ways to compare entries in a Map.

Two new utilities let you sort the entries of java hashmap by values or keys:

java sort map by value

Entry.comparingByValue

java sort map by key

Entry.comparingByKey

java sortedmap example

Map<String, String> favouriteMovies
= Map.ofEntries(entry("Raphael", "Star Wars"),
entry("Cristina", "Matrix"),
entry("Olivia",
"James Bond"));
favouriteMovies
.entrySet()
.stream()
.sorted(Entry.comparingByKey())
.forEachOrdered(System.out::println);

outputs, in order:

Cristina=Matrix
Olivia=James Bond
Raphael=Star Wars

HashMap and Performance
The internal structure of a HashMap was updated in Java 8 to improve performance.
Entries of a map typically are stored in buckets accessed by the generated hashcode
of the key. But if many keys return the same hashcode, performance deteriorates
because buckets are implemented as LinkedLists with O(n) retrieval. Nowadays,
when the buckets become too big, they’re replaced dynamically with sorted trees,
which have O(log(n)) retrieval and improve the lookup of colliding elements. Note
that this use of sorted trees is possible only when the keys are Comparable (such
as String or Number classes).

Another common pattern is how to act when the key you’re looking up in the Map isn’t present. The new getOrDefault java method can help.

Getordefault Java

When the key you’re looking up isn’t present, you receive a null reference that you have to check against to prevent a NullPointerException. A common design style is to provide a default value instead. Now you can encode this idea more simply by using the getOrDefault method. The
getOrDefault method takes the key as the first argument and a default value (to be used when the key is absent from the Map) as the second argument:

Map<String, String> favouriteMovies
= Map.ofEntries(entry("Raphael", "Star Wars"),
entry("Olivia", "James Bond"));
System.out.println(favouriteMovies.getOrDefault("Olivia", "Matrix"));
System.out.println(favouriteMovies.getOrDefault("Thibaut", "Matrix"));

Note that if the key existed in the Map but was accidentally associated with a null value, getOrDefault java can still return null. Also note that the expression you pass as a fallback
is always evaluated, whether the key exists or not.
Java 8 also included a few more advanced patterns to deal with the presence and
absence of values for a given key. You will learn about these new methods in the next
section.

Map Compute Java

Sometimes, you want to perform an operation conditionally and store its result, depending on whether a key is present or absent in a java Map. You may want to cache the result of an expensive operation given a key, for example. If the key is present, there’s no need to recalculate the result. Three new operations can help:

  • computeIfAbsent—If there’s no specified value for the given key (it’s absent or its value is null), calculate a new value by using the key and add it to the Map.
  • computeIfPresent—If the specified key is present, calculate a new value for it and add it to the Map.
  • compute—This operation calculates a new value for a given key and stores it in the Map.

One use of computeIfAbsent is for caching information. Suppose that you parse each line of a set of files and calculate their SHA-256 representation. If you’ve processed the data previously, there’s no need to recalculate it.

Now suppose that you implement a cache by using a Map, and you use an instance of MessageDigest to calculate SHA-256 hashes:

Map<String, byte[]> dataToHash = new HashMap<>();
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");

Then you can iterate through the data and cache the results:

lines.forEach(line ->
dataToHash.computeIfAbsent(line,
this::calculateDigest));
private byte[] calculateDigest(String key) {
return messageDigest.digest(key.getBytes(StandardCharsets.UTF_8));
}

This pattern is also useful for conveniently dealing with maps that store multiple values. If you need to add an element to a Map<K, List<V>>, you need to ensure that the entry has been initialized. This pattern is a verbose one to put in place. Suppose that you want to build up a list of movies for your friend Raphael:


String friend = "Raphael";
List<String> movies = friendsToMovies.get(friend);
if(movies == null) {
movies = new ArrayList<>();
friendsToMovies.put(friend, movies);
}
movies.add("Star Wars");
System.out.println(friendsToMovies);

How can you use computeIfAbsent instead? It returns the calculated value after adding it to the Map if the key wasn’t found; otherwise, it returns the existing value. You can use it as follows:

friendsToMovies.computeIfAbsent(“Raphael”, name -> new ArrayList<>())
.add(“Star Wars”);

The computeIfPresent method calculates a new value if the current value associated with the key is present in the Map and non-null. Note a subtlety: if the function that produces the value returns null, the current mapping is removed from the Map. If you need to remove a mapping, however, an overloaded version of the remove method is better suited to the task. You learn about this method in the next section. 8.3.5 Remove patt

Java Map Remove

You already know about the remove method that lets you remove a java Map entry for a given key. Since Java 8, an overloaded version removes an entry only if the key is associated with a specific value. Previously, this code is how you’d implement this behavior (we have nothing against Tom Cruise, but Jack Reacher 2 received poor reviews):

String key = "Raphael";
String value = "Jack Reacher 2";
if (favouriteMovies.containsKey(key) &&
Objects.equals(favouriteMovies.get(key), value)) {
favouriteMovies.remove(key);
return true;
}
else {
return false;
}

Here is how you can do the same thing now, which you have to admit is much more to the point:

favouriteMovies.remove(key, value);

In the next section, you learn about ways of replacing elements in and removing elements from a Map.

Java Hashmap Replace

Map has two new methods that let you replace the entries inside a Map:

  • replaceAll—Replaces each entry’s value with the result of applying a BiFunction. This method works similarly to replaceAll on a List, which you saw earlier.
  • Replace—Lets you replace a value in the Map if a key is present. An additional overload replaces the value only if it the key is mapped to a certain value.

java replaceall example

You could format all the values in a Map as follows:

Map<String, String> favouriteMovies = new HashMap<>();
favouriteMovies.put("Raphael", "Star Wars");
favouriteMovies.put("Olivia", "james bond");
favouriteMovies.replaceAll((friend, movie) -> movie.toUpperCase());
System.out.println(favouriteMovies);

The Java Hashmap Replace you’ve learned work with a single Map. But what if you have to combine and Java Hashmap Replace values from two Maps? You can use a new merge method for that task.

Java Map Merge

Suppose that you’d like to merge two intermediate Maps, perhaps two separate Maps for two groups of contacts. You can use putAll as follows:

Map<String, String> family = Map.ofEntries(
entry("Teo", "Star Wars"), entry("Cristina", "James Bond"));
Map<String, String> friends = Map.ofEntries(
entry("Raphael", "Star Wars"));
Map<String, String> everyone = new HashMap<>(family);
everyone.putAll(friends);
System.out.println(everyone);

This code works as expected as long as you don’t have duplicate keys. If you require more flexibility in how values are combined, you can use the new merge method. java map merge method takes a BiFunction to java map merge values that have a duplicate key. Suppose that Cristina is in both the family and friends maps but with different associated movies:

Map<String, String> family = Map.ofEntries(
entry("Teo", "Star Wars"), entry("Cristina", "James Bond"));
Map<String, String> friends = Map.ofEntries(
entry("Raphael", "Star Wars"), entry("Cristina", "Matrix"));

Then you could use the merge method in combination with forEach to provide a way to deal with the conflict. The following code concatenates the string names of the two movies:

Map<String, String> everyone = new HashMap<>(family);
friends.forEach((k, v) ->
everyone.merge(k, v, (movie1, movie2) -> movie1 + " & " + movie2));
System.out.println(everyone);

Note that the merge method has a fairly complex way to deal with nulls, as specified in the Javadoc:

If the specified key is not already associated with a value or is associated with null, [merge] associates it with the given non-null value. Otherwise, [merge] replaces the associated value with the [result] of the given remapping function, or removes [it] if the result is null

You can also use merge to implement initialization checks. Suppose that you have a Map for recording how many times a movie is watched. You need to check that the key representing the movie is in the map before you can increment its value:

Map<String, Long> moviesToCount = new HashMap<>();
String movieName = "JamesBond";
long count = moviesToCount.get(movieName);
if(count == null) {
moviesToCount.put(movieName, 1);
}
else {
moviesToCount.put(moviename, count + 1);
}

This code can be rewritten as

moviesToCount.merge(movieName, 1L, (key, count) -> count + 1L);

java map merge values

The second argument to java map merge in this case is 1L. The Javadoc specifies that this argument is “the non-null value to be merged with the existing value associated with the key or, if no existing value or a null value is associated with the key, to be associated with the key.” Because the value returned for that key is null, the value 1 is provided first time around. The next time around, because the value for the key was initialized to the value of 1, the BiFunction is applied to increment the count.

Keywords:

Iterate Hashmap In Java,forEach java iterator example,Java Sort Hashmap,java sortedmap example,Getordefault Java,Map Compute Java,Java Map Remove,Java Hashmap Replace,Java Map Merge.