-1

I want to make generic function which fill up HashMap by either Integer or Double values depending on the type of parameter

basically I would like to put these two functions into one generic:

public static void MapFromString_Double( Map<String,Double> mp String s ){ 
    String [] words     = s.split("\\s+");
    for ( int i=0; i<words.length; i++ ){
        String [] tuple    = s.split("=");
        String name_string = tuple[0];
        String val_string  = tuple[1];
        Double num         = Double.parseDouble( val_string );
        mp.put( name_string, num ); 
    }
}

public static void MapFromString_Integer( Map<String,Integer> mp, String s ){ 
    String [] words     = s.split("\\s+");
    for ( int i=0; i<words.length; i++ ){
        String [] tuple    = s.split("=");
        String name_string = tuple[0];
        String val_string  = tuple[1];
        Integer num        = Integer.parseInt( val_string );
        mp.put( name_string, num ); 
    }
}

The input String s should be like IronOre=10.0 Coal=30.0 LimeStone=20.0

A non working code which ilustrates what I want si this:

public static <NUM extends Number> 
void MapFromString( Map<String,NUM> mp, String s ){ 
    String [] words     = s.split("\\s+");

    for ( int i=1; i<words.length; i++ ){
        String [] tuple = s.split("=");
        String name_string = tuple[0];
        String val_string  = tuple[1];


        // 1: is there any overriden string->Number conversion ?
        //NUM num = Number.decode( val_string );
        NUM num = Number.valueOf( val_string );

        // 2: alternative using some reflections ? Does not work either
        //NUM  num;
        //if( num instanceof Integer ){
        //  num = Integer.parseInt( val_string );
        //}else{
        //  num = Double.parseDouble( val_string );
        //}

        mp.put( name_string, num ); 
    }
}

I has probably a lot of connection to the problem that you cannot call constructor of parameter type in java, which is described here: Create instance of generic type in Java? But I'm hoping that in this simple case where parameter type is just a Number there will be some more clean way.

Community
  • 1
  • 1
Prokop Hapala
  • 2,424
  • 2
  • 30
  • 59

1 Answers1

2

You can't do that with generics, for one because of type erasure, i.e. the fact that the type of NUM is unavailable at runtime.

However, in Java 8 it would be easy for the caller to provide the value parser:

@FunctionalInterface
public interface Parser<T> {
    public T parse(String s);
}

public static <N extends Number> void MapFromString(Map<String, N> mp, String s, Parser<N> parser) {
    for (String word : s.split("\\s+")) {
        int idx = word.indexOf('=');
        mp.put(word.substring(0, idx), parser.parse(word.substring(idx + 1)));
    }
}

It would then be called like this:

Map<String, Double> doubleMap = new HashMap<>();
MapFromString(doubleMap, "...", Double::valueOf);

Map<String, Integer> integerMap = new HashMap<>();
MapFromString(integerMap, "...", Integer::valueOf);
Andreas
  • 154,647
  • 11
  • 152
  • 247