Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Runtime casting from String to other datatype

Tags:

java

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.

like image 690
Gengrlin Avatar asked May 17 '10 03:05

Gengrlin


3 Answers

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

  • int Integer.parseInt(String)
  • double Double.parseDouble(String)
  • NumberFormatException -- this may be thrown by the parseXXX

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

  • What is a raw type and why shouldn’t we use it?

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

  • How do I keep a scanner from throwing exceptions when the wrong type is entered? (java)

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.

like image 171
polygenelubricants Avatar answered Sep 29 '22 15:09

polygenelubricants


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/

like image 26
risuch Avatar answered Sep 29 '22 15:09

risuch


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

double d = Double.parseDouble("45.40");
like image 37
SLaks Avatar answered Sep 29 '22 15:09

SLaks