gru
gru

Reputation: 4569

call to map.get inside For/in loop throws nullpointerexception while iterator doesn't

I broke my brain on it for a few hours, but need to carry on and found an ugly workaround, but I'd be happy to cleanup my code, here's the problem:

public static void function1(Map<String, Float> map)
{
    for(String key : map.keySet()) {
        Float val = map.get(key);
        // val is null here, throws NPE as soon as we try to use it
    }
}

public static void function2(Map<String, Float> map)
{
    Iterator<Entry<String, Float>> it = map.entrySet().iterator();
    while(it.hasNext()) {
        Entry<String, Float> entry = it.next();
        String key = entry.getKey();
        Float val = entry.getValue();
        // do something with key & val, works fine
    }
}

the argument Map<String, Float> map of course is correctly initialized and doesn't contain any null value.

on a side note, function1 works fine if I change the argument to Map map and use string pairs only. My goal is to to have only 1 function with generics Map<? extends Object, ? extends Object> map which I could use for both type of maps.

any suggestion appreciated, thanks! thomas


EDIT: I added some really basic introspection to make the function work with generics. I can confirm that I'm still getting null values when using the keyset, while I followed the suggestion below to use the entryset. here's my code below (the 1st function works fine, while the second returns null elements.

// yeah, it's aweful, but it works.
public static JsonNode map2JSON(Map<? extends Object, ? extends Object> map)
{
    ObjectNode dummyObject = Json.newObject();
    ArrayNode result = dummyObject.putArray("dummyKey");
    for(Entry<?, ?> entry : map.entrySet()) {
        ObjectNode mapElementNode = result.addObject();
        if("java.lang.String".equalsIgnoreCase(entry.getKey().getClass().getName())) {
            String key = (String)entry.getKey();
            if("java.lang.Float".equalsIgnoreCase(entry.getValue().getClass().getName())) {
                Float val = (Float)entry.getValue();
                mapElementNode.put(key, val);
            } else if("java.lang.String".equalsIgnoreCase(entry.getValue().getClass().getName())) {
                String val = (String)entry.getValue();
                mapElementNode.put(key, val);
            }
        }
    }
    return result;
}

// result here contains valid keys (the string part) and null values (the float part)
@Deprecated
public static JsonNode mapSF2JSON(Map<String, Float> map)
{
    ObjectNode dummyObject = Json.newObject();
    ArrayNode result = dummyObject.putArray("dummyKey");
    for(String key : map.keySet()) {
        ObjectNode mapElementNode = result.addObject();
        mapElementNode.put(key, map.get(key));
    }
    return result;
}

Upvotes: 2

Views: 3270

Answers (2)

AlexWien
AlexWien

Reputation: 28757

function1 uses a foreach loop, which will throw a NullPointerException when the map is null. You should check the map to be not null before you iterate with foreach

Further You should rewrite the ugly

if("java.lang.String".equalsIgnoreCase(entry.getKey().getClass().getName())) {

to

 if (entry.getKey().getClass() == String.class) {

Upvotes: 0

AlexWien
AlexWien

Reputation: 28757

You probably inserted NULL key Strings into the map. This is possible when using a HashMap. Try to avoid adding NULL keys. Further you could use a TreeMap.

Bye the way it is not bad to iterate over the entry set, you could clean up your code by using foreach in function2 like you have done in function1:

This will look something like:

for(Entry<String, Float> entry : map.entrySet()) {
    Float val = entry.getValue();
}

Although it is not necessary to clean up function2. But you should find the location where you inserted the NULL key into the map.

Upvotes: 1

Related Questions