Apache Commons Collections MapUtils

1. Introduction

MapUtils is one of the tools available in the Apache Commons Collections project.

Simply put, it provides utility methods and decorators to work with java.util.Map and java.util.SortedMap instances.

2. Setup

Let’s start by adding the dependency:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.1</version>
</dependency>

3. Utility Methods

3.1. Creating a Map from an Array

Now, let’s set up arrays that we will use for creating a map:

public class MapUtilsTest {
    private String[][] color2DArray = new String[][] {
        {"RED", "#FF0000"},
        {"GREEN", "#00FF00"},
        {"BLUE", "#0000FF"}
    };
    private String[] color1DArray = new String[] {
        "RED", "#FF0000",
        "GREEN", "#00FF00",
        "BLUE", "#0000FF"
    };
    private Map<String, String> colorMap;

    //...
}

Let’s see how we can create a map from a two-dimensional array:

@Test
public void whenCreateMapFrom2DArray_theMapIsCreated() {
    this.colorMap = MapUtils.putAll(
      new HashMap<>(), this.color2DArray);

    assertThat(
      this.colorMap, 
      is(aMapWithSize(this.color2DArray.length)));
    
    assertThat(this.colorMap, hasEntry("RED", "#FF0000"));
    assertThat(this.colorMap, hasEntry("GREEN", "#00FF00"));
    assertThat(this.colorMap, hasEntry("BLUE", "#0000FF"));
}

We could also use a one-dimensional array. In that case, the array is treated as keys and values in alternate indices:

@Test
public void whenCreateMapFrom1DArray_theMapIsCreated() {
    this.colorMap = MapUtils.putAll(
      new HashMap<>(), this.color1DArray);
    
    assertThat(
      this.colorMap, 
      is(aMapWithSize(this.color1DArray.length / 2)));

    assertThat(this.colorMap, hasEntry("RED", "#FF0000"));
    assertThat(this.colorMap, hasEntry("GREEN", "#00FF00"));
    assertThat(this.colorMap, hasEntry("BLUE", "#0000FF"));
}

3.2. Printing the Content of a Map

Many times while debugging or in debug logs, we would like to print the entire map:

@Test
public void whenVerbosePrintMap_thenMustPrintFormattedMap() {
    MapUtils.verbosePrint(System.out, "Optional Label", this.colorMap);
}

And the result:

Optional Label = 
{
    RED = #FF0000
    BLUE = #0000FF
    GREEN = #00FF00
}

We can also use debugPrint() which additionally prints the data types of the values.

3.3. Getting Values

MapUtils provides some methods for extracting value from a map for a given key in a null-safe manner.

For example, getString() gets a String from the Map. The String value is obtained via toString(). We can optionally specify the default value to be returned if the value is null or if the conversion fails:

@Test
public void whenGetKeyNotPresent_thenMustReturnDefaultValue() {
    String defaultColorStr = "COLOR_NOT_FOUND";
    String color = MapUtils
      .getString(this.colorMap, "BLACK", defaultColorStr);
    
    assertEquals(color, defaultColorStr);
}

Note that these methods are null-safe i.e. they can safely handle the null map parameter:

@Test
public void whenGetOnNullMap_thenMustReturnDefaultValue() {
    String defaultColorStr = "COLOR_NOT_FOUND";
    String color = MapUtils.getString(null, "RED", defaultColorStr);
    
    assertEquals(color, defaultColorStr);
}

Here the color would get the value as COLOR_NOT_FOUND even though the map is null.

3.4. Inverting the Map

We can also easily reverse a map:

@Test
public void whenInvertMap_thenMustReturnInvertedMap() {
    Map<String, String> invColorMap = MapUtils.invertMap(this.colorMap);

    int size = invColorMap.size();
    Assertions.assertThat(invColorMap)
      .hasSameSizeAs(colorMap)
      .containsKeys(this.colorMap.values().toArray(new String[] {}))
      .containsValues(this.colorMap.keySet().toArray(new String[] {}));
}

This would invert the colorMap to:

{
    #00FF00 = GREEN
    #FF0000 = RED
    #0000FF = BLUE
}

If the source map associates same value for multiple keys then after inversion one of the values will become a key randomly.

3.5. Null and Empty Checks

isEmpty() method returns true if a Map is null or empty.

safeAddToMap() method prevents addition of null elements to a Map.

4. Decorators

These methods add additional functionality to a Map.

In most cases, it’s good practice not to store the reference to the decorated Map.

4.1. Fixed-Size Map

fixedSizeMap() returns a fixed-size map backed by the given map. Elements can be changed but not added or removed:

@Test(expected = IllegalArgumentException.class)
public void whenCreateFixedSizedMapAndAdd_thenMustThrowException() {
    Map<String, String> rgbMap = MapUtils
      .fixedSizeMap(MapUtils.putAll(new HashMap<>(), this.color1DArray));
    
    rgbMap.put("ORANGE", "#FFA500");
}

4.2. Predicated Map

The predicatedMap() method returns a Map ensures that all held elements match the provided predicate:

@Test(expected = IllegalArgumentException.class)
public void whenAddDuplicate_thenThrowException() {
    Map<String, String> uniqValuesMap 
      = MapUtils.predicatedMap(this.colorMap, null, 
        PredicateUtils.uniquePredicate());
    
    uniqValuesMap.put("NEW_RED", "#FF0000");
}

Here, we specified the predicate for values using PredicateUtils.uniquePredicate(). Any attempt to insert a duplicate value into this map will result in java.lang.IllegalArgumentException.

We can implement custom predicates by implementing the Predicate interface.

4.3. Lazy Map

lazyMap() returns a map where values are initialized when requested.

If a key passed to this map’s Map.get(Object) method is not present in the map, the Transformer instance will be used to create a new object that will be associated with the requested key:

@Test
public void whenCreateLazyMap_theMapIsCreated() {
    Map<Integer, String> intStrMap = MapUtils.lazyMap(
      new HashMap<>(),
      TransformerUtils.stringValueTransformer());
    
    assertThat(intStrMap, is(anEmptyMap()));
    
    intStrMap.get(1);
    intStrMap.get(2);
    intStrMap.get(3);
    
    assertThat(intStrMap, is(aMapWithSize(3)));
}

5. Conclusion

In this quick tutorial, we have explored the Apache Commons Collections MapUtils class and we looked at various utility methods and decorators that can simplify various common map operations.

As usual, the code is available over on GitHub.

Related posts:

Java Program to Implement Graph Structured Stack
Java 8 – Powerful Comparison with Lambdas
ExecutorService – Waiting for Threads to Finish
Java Program to Implement Multi-Threaded Version of Binary Search Tree
The Spring @Controller and @RestController Annotations
Guide to java.util.Formatter
Java Program to Describe the Representation of Graph using Incidence Matrix
Spring – Injecting Collections
Marker Interface trong Java
Hướng dẫn sử dụng luồng vào ra ký tự trong Java
REST Web service: Basic Authentication trong Jersey 2.x
Java Program to Find the Shortest Path Between Two Vertices Using Dijkstra’s Algorithm
Java Program to Implement Sorted Singly Linked List
Java Program to Generate a Sequence of N Characters for a Given Specific Case
A Guide to ConcurrentMap
Sử dụng CountDownLatch trong Java
Java Program to Apply DFS to Perform the Topological Sorting of a Directed Acyclic Graph
Hướng dẫn sử dụng Java String, StringBuffer và StringBuilder
Spring’s RequestBody and ResponseBody Annotations
Guide to the Synchronized Keyword in Java
Guide to DelayQueue
Guide to UUID in Java
Create a Custom Auto-Configuration with Spring Boot
Java Program to Check if a Matrix is Invertible
Testing in Spring Boot
Guide to Spring Cloud Kubernetes
Spring Boot - Database Handling
Java Program to Implement Wagner and Fisher Algorithm for online String Matching
Request Method Not Supported (405) in Spring
Introduction to Spring Cloud Stream
Guide to java.util.concurrent.Future
New Features in Java 13