5

Hi I have Map of String values.

I want to cast this value at runtime.

e.g.

Map map = new HashMap();
map.put("key1","101");
map.put("key2","45.40");

Now runtime I know key1 is integer and key2 is double How can I cast this.

I tried this:

("101").getClass().cast(Integer).

////////////////////////////////////////////// e.g. ...........

String integerClass = "java.lang.Integer"; String strNum = "5"; Now How will you convert this strNum value "5" to Integer using integerClass.

.....Without using new Integer(strNum) directly

Thanks.

Gengrlin
  • 81
  • 1
  • 4

8 Answers8

8

You can't linguistically cast a String (a reference type) to an int or a double (a primitive numeric type). You'd have to convert them. Thankfully, there are standard methods to do them for you:

API links

Note

T Class<T>.cast(Object) does something entirely different. It has to do with generics, reflection, type-tokens, etc.


That said, I noticed that you used a raw Map type. Since this looks like a new code, it should be said that you should NOT use raw types in new code. It's possible that you may never need to convert from String to int/double in the first place (or at least do it BEFORE you put them into the map).

A Map<String,Number> (or perhaps a Map<String,Double>) would be better, because the map is "type-safe"; you know it maps String to Number, and the compiler would ensure that you're not doing anything to violate this type invariant.

Related questions


Based on OP's comments, it looks like something like this was desired:

import java.util.*;
public class MapTranslate {
    static Object interpret(String s) {
        Scanner sc = new Scanner(s);
        return
            sc.hasNextInt() ? sc.nextInt() :
            sc.hasNextLong() ? sc.nextLong() :
            sc.hasNextDouble() ? sc.nextDouble() :
            sc.hasNext() ? sc.next() :
            s;
    }
    public static void main(String[] args) {
        Map<String,String> map1 = new HashMap<String,String>();
        map1.put("One", "1");
        map1.put("PI", "3.141592653589793");
        map1.put("10^12", "1000000000000");
        map1.put("Infinity", "oo");
        map1.put("Blank", "   ");

        Map<String,Object> map2 = new HashMap<String,Object>();
        for (Map.Entry<String,String> entry : map1.entrySet()) {
            map2.put(entry.getKey(), interpret(entry.getValue()));
        }

        for (Map.Entry<String,Object> entry: map2.entrySet()) {
            System.out.format("%s->[%s] (%s)%n",
                entry.getKey(),
                entry.getValue(),
                entry.getValue().getClass().getSimpleName()
            );
        }
    }
}

This produces:

PI->[3.141592653589793] (Double)
Infinity->[oo] (String)
One->[1] (Integer)
10^12->[1000000000000] (Long)
Blank->[   ] (String)

This is not the most robust (e.g. it doesn't handle null keys/values), but it may be a good starting point. Note that it uses java.util.Scanner and its hasXXX methods; this way you don't have to worry about any NumberFormatException.

Without understanding the big picture, though, it's hard to comment whether something like this is even a good idea to begin with.

Related questions


Using reflection

This seems to also be an aspect of the question; the following should be instructive:

import java.lang.reflect.*;

public class ValueOfString {
    static <T> T valueOf(Class<T> klazz, String arg) {
        Exception cause = null;
        T ret = null;
        try {
            ret = klazz.cast(
                klazz.getDeclaredMethod("valueOf", String.class)
                .invoke(null, arg)
            );
        } catch (NoSuchMethodException e) {
            cause = e;
        } catch (IllegalAccessException e) {
            cause = e;
        } catch (InvocationTargetException e) {
            cause = e;
        }
        if (cause == null) {
            return ret;
        } else {
            throw new IllegalArgumentException(cause);
        }
    }
    public static void main(String[] args) throws ClassNotFoundException {
        Integer ii = valueOf(Integer.class, "42"); // no need to cast!
        System.out.println(ii); // prints "42"

        Object o = valueOf(Class.forName("java.lang.Double"), "3.14159");
        System.out.println(o);
        System.out.println(o instanceof Double); // prints "true"       
    }
}

The above snippet uses type tokens and reflections to invoke static valueOf(String) method. The use of reflection may not be justifiable in this case, however, and it may simply be better to just explicitly check what the desired conversion is, e.g. "java.lang.Integer", and then invoke Integer.valueOf accordingly.

Community
  • 1
  • 1
polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
  • I don't want to cast to any primitive datatype. – Gengrlin May 17 '10 at 04:19
  • @Gengrlin: see latest revision and tell me if it helps. – polygenelubricants May 17 '10 at 04:23
  • @Gengrlin: also, `int` and `double` are primitive datatypes, and your original question seemed to indicate that this _conversion_ is what you wanted to do. Please clarify your intention; I will do everything I can to help. – polygenelubricants May 17 '10 at 04:38
  • Thanks This is closest solution but.... Here is what I want to do...... I am storing datatype of parameters in db and i am getting values from client side in string so now runtime I want to convert this string values to required datatype. //////////////// example .. String integerClass = "java.lang.Integer"; String strNum = "5"; ............. Now How will you convert this strNum value "5" to Integer using integerClass. .....Without using new Integer(strNum) directly – Gengrlin May 17 '10 at 04:39
  • @Gengrlin: what other types are there besides `java.lang.Integer`? – polygenelubricants May 17 '10 at 04:44
2

I had a similar problem and solved it using the GenericValidator Helper Class from the Apache Commons Project to find out what Datatype I assume could be in the string and then parse it.

public Object parseString(String myString) {

        if (GenericValidator.isLong(myString)) {
            return Long.parseLong(myString);
        } else if (GenericValidator.isDouble(myString)) {
            return Double.parseDouble(myString);
        } else if (GenericValidator.isDate(myString, Locale.GERMAN)) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("DD.MM.YYYY");
            return  LocalDate.parse(myString, formatter);
        } else {
            return myString;
        }
}

https://commons.apache.org/proper/commons-validator/

Jared Burrows
  • 54,294
  • 25
  • 151
  • 185
risuch
  • 420
  • 7
  • 14
1

You need to parse the string into a double, like this:

double d = Double.parseDouble("45.40");
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Let me explain you in details....... My situation is: I have two map at RunTime::: 1st Map: key and valueClass....... 2nd Map: key and value (value in string) .......... Now Runtime I want to cast string values of 2nd map as per required 1st map ValueClass can be any datatype (Integer, String,Double, Long etc) – Gengrlin May 17 '10 at 04:02
  • You're misusing the word runtime. I have no idea what you're asking. – SLaks May 17 '10 at 04:13
0

the cast method on Object will do an instanceof test, and as you probably know, will throw a ClassCastException in this case. What you can do is the use the constructors for Double and Integer that take String arguements.

akf
  • 38,619
  • 8
  • 86
  • 96
  • Okay here is one another sample. String integerClass = "java.lang.Integer"; String strNum = "5"; ............. Now How will you convert this strNum value "5" to Integer using integerClass. .....Without using new Integer(strNum) directly – Gengrlin May 17 '10 at 04:34
  • That would be useless, because you can't do anything with it unless you know the type at compile time. – SLaks May 17 '10 at 04:36
0

You can use Integer.parseInt and Double.parseDouble

int value1 = Integer.parseInt(map.get("key1"));
double value2 = Double.parseDouble(map.get("key2"));
lavinio
  • 23,931
  • 5
  • 55
  • 71
  • Its not that simple. Its runtime so I am getting on Class of any datatype and based on datatype received value must be converted – Gengrlin May 17 '10 at 04:43
0

You cannot cast a String to any other type, you must convert it. For example, to convert to an Integer:

Integer value = Integer.valueOf(string);

For Double:

Double value = Double.valueOf(string);
Kevin Brock
  • 8,874
  • 1
  • 33
  • 37
0

OK, after reading the additional comments, I think you are after something like this:

static Number convertNumber(String className, String value)
  throws NoSuchMethodException, InvocationTargetException, 
    IllegalArgumentException, IllegalAccessException, ClassNotFoundException {
  Class<?> clazz = Class.forName(className);
  Method method = clazz.getDeclaredMethod("valueOf", String.class);
  return (Number)method.invoke(clazz, value);
}

Which you could use like this:

Map<String, String> map1 = new HashMap<String, String>();
Map<String, String> map2 = new HashMap<String, String>();
map1.put("key1", "java.lang.Integer");
map2.put("key1","101");
map1.put("key2", "java.lang.Double");
map2.put("key2","45.40");

try {
  Number value;
  value = convertNumber(map1.get("key1"), map2.get("key1"));
  System.out.format("Value = %s, type = %s\n", value, value.getClass().getSimpleName());
  value = convertNumber(map1.get("key2"), map2.get("key2"));
  System.out.format("Value = %s, type = %s\n", value, value.getClass().getSimpleName());
  value = convertNumber("java.lang.Integer", "foo!");
  System.out.format("Value = %s, type = %s\n", value, value.getClass().getSimpleName());
} catch (Exception e) {
  e.printStackTrace(System.out);
}
clstrfsck
  • 14,715
  • 4
  • 44
  • 59
0

If I understood your problem correctly, I think you could use Java Reflection to create new objects. Invoking the Constructor is equivalent to creating new objects.

Map<Integer, String> typeMap = new HashMap<Integer, String>();

Map<Integer, String> valueMap = new HashMap<Integer, String>();

typeMap.put(1, "java.lang.Double");

valueMap.put(1, "10");

Class clazz = Class.forName((String) typeMap.get(1));

Constructor constructor = clazz.getConstructor(String.class);

Object obj = constructor.newInstance(valueMap.get(1));

Community
  • 1
  • 1
user184794
  • 1,036
  • 9
  • 15