Search code examples
javasonarqubeoption-type

Best way to call isPresent on Java Optional


I have the following code on which sonar is throwing a check "Optional#isPresent()" before accessing value error.

private Map<String, Map<String, Object>> generateMap(Object object) {
    return Optional.ofNullable((List<Map<String, Object>>) object).map((obj) -> functionListToMap.apply(obj)).get();
}

I've tried the following the way to fix the error, but I'm not sure if this is the best coding standard.

private Map<String, Map<String, Object>> generateMap(Object object) {
    Optional<List<Map<String, Object>>> result = Optional.ofNullable((List<Map<String, Object>>) object);
    if(result.isPresent()) {
        return result.map((obj) -> functionListToMap.apply(obj)).get();
    }
    else {
        return null;
    }
}

Can someone please suggest is there is any other best way to do this?


Solution

  • The unchecked cast is something you should try to avoid. If you know that your method can only handle List<Map<String, Object>>, then your parameter should be typed as such.

    I'm assuming functionListToMap is a Function<>. Calling it like that (functionListToMap.apply()) almost defeats the purpose of a functional interface. Instead, just use it as a lambda.

    In this case, where you just want to return null if there is no data, you can use orElse():

    private Map<String, Map<String, Object>> generateMap(List<Map<String, Object>> list) {
        return Optional.ofNullable(list).map(functionListToMap).orElse(null);
    }
    

    In the case you want to return an empty Map if no data is present, use orElseGet() instead:

    private Map<String, Map<String, Object>> generateMap(List<Map<String, Object>> list) {
        return Optional.ofNullable(list).map(functionListToMap).orElseGet(HashMap::new);
    }
    

    The difference from using orElse(new HashMap<>()) is that in the case of orElse, the other object is instantiated every time, regardless of whether it is used or not, while with orElseGet() the Supplier (HashMap::new) is only called if needed.

    You could also rewrite the method without Optional:

    private Map<String, Map<String, Object>> generateMap(List<Map<String, Object>> list) {
        if (list == null) {
            return null;
        } else {
            return functionListToMap.apply(list);
        }
    

    }

    Or again, but also rewrite functionListToMap to be a method:

    private Map<String, Map<String, Object>> generateMap(List<Map<String, Object>> list) {
        if (list == null) {
            return null;
        } else {
            return functionListToMap(list);
        }
    }