Home > Net >  Overcoming Sonar issue replace Map.get() and condition with a call to Map.computeIfAbsent()
Overcoming Sonar issue replace Map.get() and condition with a call to Map.computeIfAbsent()

Time:12-18

I have a below method. The implementation is if the map does not have id key, then the method inserts id and name.

But Sonar reports this line of code as a Major error and suggests to replace Map.get() and condition with a call to Map.computeIfAbsent().

How to insert values into map using computeIfAbsent?

Original Code

Here Sonar complains:

public void testMethod(List<Map<String, Object>> restultMapList) {
    for(Map<String, Object> resultMap : restultMapList) {
        if(resultMap.get("id")==null) {
            resultMap.put("id", "");
            resultMap.put("name", "");
        }
    }
}

Attempt to use computeIfAbsent

I have tried the below but it throws error. Not sure how to fix this.

public void testMethod(List<Map<String, Object>> restultMapList) {
    for(Map<String, Object> resultMap : restultMapList) {
        resultMap.computeIfAbsent("id", x-> x.put("id",""));
    }
}

Then following errors are shown:

Multiple markers at this line
    - Lambda expressions are allowed only at source level 1.8 or above
    - The method put(String, String) is undefined for the type String

CodePudding user response:

Just return the String value from the lambda function without any operations.

Alternatively, using putIfAbsent would make more sense as there in no computation involved. computeIfAbsent makes more sense where getting the value would involve some operation (e.g. in cache, if not present fetch from original source).

resultMap.putIfAbsent("id", "");

As for computeIfAbsent,

For reference, Method's Javadoc says

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.

Thus in your case, there is no computation as such - so you can return the string itself. The definition of the function is:

Params: key – key with which the specified value is to be associated

mappingFunction – the function to compute a value

Returns: the current (existing or computed) value associated with the specified key, or null if the computed value is null

The following snippet will work for you:

Map<String, String> resultMap = new HashMap<>();
resultMap.computeIfAbsent("id", s -> "FirstValue");
System.out.println(resultMap.get("id"));             // FirstValue
resultMap.computeIfAbsent("id", s -> "NewValue");
System.out.println(resultMap.get("id")); 
// Still FirstValue as id was already present

Here the Lamda s -> "NewValue" can be expanded to (String s) -> "NewValue"

For the second part - the error "Lambda expressions are allowed only at source level 1.8 or above" indicates wrong environment in IDE probably, where you would need to set language API level to 1.8 or above, or check the library settings.

CodePudding user response:

The Rule

The Sonar rule for Java with RSPEC-3824 applies for Java 8 only:

"Map.get" and value test should be replaced with single method call

It’s a common pattern to test the result of a java.util.Map.get() against null or calling java.util.Map.containsKey() before proceeding with adding or changing the value in the map. However the java.util.Map API offers a significantly better alternative in the form of the computeIfPresent() and computeIfAbsent() methods. Using these instead leads to cleaner and more readable code.

Note that this rule is automatically disabled when the project’s sonar.java.source is not 8.

Let's assume your project is configured for the use of Java 8.

The Sonar compliant solution

From:

if (resultMap.get("id") == null) {
    resultMap.put("id", "");
    resultMap.put("name", "");
}

To use with putIfAbsent(key, value):

resultMap.putIfAbsent("id", "");  // empty string as default

Note:

  • this solution does not compute anything, no lambda needed.
  • here resultMap.put("name", ""); is not called if key "id" was not present.

Both methods putIfAbsent and computeIfAbsent were added to interface Map with Java version 8.

See also:

  • Related