Java Generators and Numeric Types

I would like to create a universal method that does this efficiently:

class MyClass { static <T extends Number> T sloppyParseNumber(String str) { try { return T.valueOf(str); } catch (Exception e) { return (T)0; } } } 

Now the above does not compile for two reasons: there is no Number.valueOf() method, and 0 cannot be attributed to T

Usage example:

 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 the implementation of the Java method higher than the general method? If so, how? If not, what is a good alternative approach?


Edit: there seem to be several possible duplicates, but I have not found one that covers just that. I hope you manage to do some sort of trick that would allow these two operations: split the string into a subclass of Number and return the value 0 for the subclass of Number .

+7
source share
5 answers

I agree 100% with TofuBeer. But if you want to avoid verbosity over time, 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 only from T you cannot get the type at runtime.

+3
source

Java generators provide only compile-time checks, and data type information is largely thrown away after compilation. Thus, the statement T.valueOf not possible in Java. The solution is to go in a detailed way, as mentioned in the comments. Also, is there a reason you want to make MyClass.<Double>sloppyParseNumber(value) , but not MyClass.sloppyParseDouble(value) , since you still specify the type at compile time?

+3
source

Static methods are type-bound, because at best, Number and Number do not have a valueOf method, so you are not going to work after that.

The easiest way is to just make some static methods like sloppyParseInt , sloppyParseFloat etc.

You can do something like this, not sure I like it, and probably can be improved:

 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; } } } 
+2
source

So, I decided on an alternative approach:

 static String trimTo0(String str) { if (str == null) return "0"; str = str.trim(); if (str.isEmpty()) return "0"; return str; } 

Using:

 String value = null; System.out println("Double value: " + Double.parseDouble(trimTo0(value))); 

Note that this is more limited than the method in question, it does not convert invalid, non-numeric strings to "0" . This will require two different methods, one of which contains a decimal point, and the other only integers.

0
source

You can try the following:

 private <T> T convertToType(Class<T> clazz,String str) throws Exception { return clazz.getConstructor(String.class).newInstance(str); } 

Here you need to consider that the type must have a constructor with the String parameter.

0
source

All Articles