I'd like to create a generic method which does effectively this:
class MyClass {
static <T extends Number> T sloppyParseNumber(String str) {
try {
return T.valueOf(str);
} catch (Exception e) {
return (T)0;
}
}
}
Now above does not compile for two reasons: there's no Number.valueOf()
method and 0 can't be cast to T
.
Example usage:
String value = "0.00000001";
System.out.println("Double: " + MyClass.<Double>sloppyParseNumber(value));
System.out.println("Float: " + MyClass.<Float>sloppyParseNumber(value));
double d = MyClass.sloppyParseNumber(value);
float f = MyClass.sloppyParseNumber(value);
Is implementing above generic method possible with Java? If yes, how? If no, what's a good alternative approach?
Edit: there seems to be a few possible duplicates, but I did not find one, which covers exactly this. I'm hoping there's some trick to pull, which would allow these two operations: parse string to a Number
subclass, and return 0 value for a Number
subclass.
I agree 100% with TofuBeer. But in case you wish to avoid verbosity for time sake, this should also do:
static <T extends Number> T sloppyParseNumber(String str,Class<T> clas) {
if (clas == null) throw new NullPointerException("clas is null");
try {
if(clas.equals(Integer.class)) {
return (T) Integer.valueOf(str);
}
else if(clas.equals(Double.class)) {
return (T) Double.valueOf(str);
}
//so on
catch(NumberFormatException|NullPointerException ex) {
// force call with valid arguments
return sloppyParseNumber("0", clas);
}
throw new IllegalArgumentException("Invalid clas " + clas);
}
But purely from T
, you cannot get the type at runtime.
Java generics only provide compile time checks and the type information is pretty much thrown away after compilation. So the statement T.valueOf
isn't possible in Java. The solution is to go the verbose way as already mentioned in the comments. Also, is there any reason why you want to do MyClass.<Double>sloppyParseNumber(value)
but not MyClass.sloppyParseDouble(value)
since you are anyway specifying the type at compile time?
Static methods are bound by the type, since the type is, at best, Number
and Number
doesn't have a valueOf
method what you are after isn't going to work.
The easiest way is to just make a number of static methods like sloppyParseInt
, sloppyParseFloat
, etc...
You could do something like this, not sure I like it, and can probably be improved on:
public class Main
{
private static final Map<Class<? extends Number>, NumberConverter> CONVERTERS;
static
{
CONVERTERS = new HashMap<>();
CONVERTERS.put(Integer.class, new IntegerConverter());
}
public static void main(String[] args)
{
Number valueA;
Number valueB;
valueA = CONVERTERS.get(Integer.class).convert("42");
valueB = CONVERTERS.get(Integer.class).convert("Hello, World!");
System.out.println(valueA);
System.out.println(valueB);
}
}
interface NumberConverter<T extends Number>
{
T convert(String str);
}
class IntegerConverter
implements NumberConverter<Integer>
{
@Override
public Integer convert(String str)
{
try
{
return Integer.valueOf(str);
}
catch (NumberFormatException ex)
{
return 0;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With