peterboston
peterboston

Reputation: 927

how to convert a <String, Float>Map toString method to a generic Number version

I have a method to get the contents of the Map as a String, like this:

    public static String toStringStringFloatMap(Map<String, Float> stringFloatMap)
    {
        String entries = "";

        Iterator<Entry<String, Float>> it = stringFloatMap.entrySet().iterator();
        while (it.hasNext())
        {
            Map.Entry<String, Float> pair = it.next();
            entries += pair.getKey() + "=" + pair.getValue() + "\n";
        }

        return entries;
    }

Now I am trying to convert it to a generic version for Integer, Short, Double, .... . I have replaced all Float with "? extends Number" but the ....entrySet().iterator(); statement causes compile error and tells me the following:

Type mismatch: cannot convert from Iterator<Map.Entry<String,capture#6-of ? extends Number>> to Iterator<Map.Entry<String,? extends Number>>

I don't know what that "captured#6-of ? extends Number" means. anyone can explain it for me?

EDIT:

As Andy points out that the <?, ?> may be the best.

But my question is still that why the iterator() line cannot pass the compiler?

    public static String toStringMapError(Map<?, ?> map)
    {
        String entries = "";

        Iterator<Entry<?, ?>> it = map.entrySet().iterator(); <<<<<------- error lineeeeeee
        while (it.hasNext())
        {
            Map.Entry<?, ?> pair = it.next();
            entries += pair.getKey() + "=" + pair.getValue() + "\n";
        }

        return entries;
    }

Upvotes: 3

Views: 536

Answers (2)

Nir Levy
Nir Levy

Reputation: 12953

You shouldn't replace Float with ? extends Number, instead, define a generic type in your method and use it:

public static <T extends Number> String toStringStringFloatMap(Map<String, T> stringFloatMap)
    {
        String entries = "";

        Iterator<Map.Entry<String, T>> it = stringFloatMap.entrySet().iterator();
        while (it.hasNext())
        {
            Map.Entry<String, T> pair = it.next();
            entries += pair.getKey() + "=" + pair.getValue() + "\n";
        }

        return entries;
    }

Upvotes: 2

Andy Turner
Andy Turner

Reputation: 140494

If you really want to constrain to subclasses of Number, declare a type variable, and use throughout:

public static <T extends Number> String toStringStringNumberMap(Map<String, T> stringFloatMap) {
    String entries = "";

    Iterator<Entry<String, T>> it = stringNumberMap.entrySet().iterator();
    while (it.hasNext())
    {
        Map.Entry<String, T> pair = it.next();
        entries += pair.getKey() + "=" + pair.getValue() + "\n";
    }

    return entries;
}

But you could simply use ? for both the key and value: there's nothing here that requires an instance of String or Number specifically: all you need is types implementing toString(), which means any subclass of Object is acceptable.

public static String toStringMap(Map<?, ?> map) { ... }

You can also use an enhanced for statement, which is neater than an explicit iterator; and you should always use a StringBuilder when accumulating strings in a loop, and avoid building unnecessary temporary strings:

StringBuilder sb = new StringBuilder();
for (Map.Entry<?, ?> entry : map.entrySet()) {
  sb.append(entry.getKey());
  sb.append('=');
  sb.append(entry.getValue());
  sb.append('\n');
}
return sb.toString();

Upvotes: 8

Related Questions