Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

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.

Next »
Guide to Apache Commons CircularFifoQueue
« Previous
A Guide to Apache Commons Collections CollectionUtils
Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are closed on this article!