Another reaction: in practice there is not much numeric about
java.lang.Number. Operationally the type means "convertible to a
primitive type" and there is nothing else extending Number lets you do
with a class. Additionally in retrospect, Number would have been better
as an interface rather than an abstract class.
When looking to augment numeric capabilities of the platform, directly
involving java.lang.Number is not the first or second place I'd look.
Cheers,
-Joe
On 3/28/2025 11:38 AM, Kevin Bourrillion wrote:
I appreciate you raising this; I think it is relevant to some internal
discussions we’re having about the future of Number. Here’s some
personal reactions from a team member (not a team consensus opinion):
Unfortunately, we’ve found many times that `Number` is a pretty
deficient return type that users can’t do much of anything useful with
(except apply arbitrarily lossy conversions to, or test with
`instanceof`).
And I’m skeptical that most users ever want to end up in a situation
where they have a `Number[]` or `Collection<Number>` that could be
heterogeneous. This state feels like a temporary one you want to get
out of.
It’s not clear that `Number` can really be rehabilitated much, either.
It is sort of a “deficient type” by its nature.
When you do need this sort of flexible parsing, I think the status quo
is: you can always parse to BigDecimal first, then ask questions about
what more “minimal” type the value you got might fit into. Obviously
this does not have optimal performance, but I am not sure there’s a
good spot-fix here that doesn’t just raise more issues than it tried
to resolve.
We will keep thinking about this, though. Valhalla means we will
inevitably have more "numeric types" than ever, and this is prompting
us to think about what these types should have in common. (It’s a big
topic and I apologize for not even attempting to outline it all for
you here yet.)
On Mar 28, 2025, at 10:29 AM, Sathish Kumar Thiyagarajan
<sathishkumar.thiyagara...@gmail.com> wrote:
Dear Core-Libs Dev Team,
*Note:* I have now subscribed to the mailing list and am resending
this message as advised.
I would like to propose an improvement to the JDK: a *generalized
|Number.parseNumber(String)| method*.
Motivation
Java provides multiple number types (|byte|, |short|, |int|, |long|,
etc.), and developers typically choose them based on memory
considerations. Currently, Java offers |String| to |Number|
conversions using concrete classes:
*
|Long.parseLong(String)|
*
|Integer.parseInt(String)|
*
|Short.parseShort(String)|, etc.
While these are useful, Java lacks a *generalized method* that
returns the most memory-efficient |Number| representation based on
the input, like:
|Number.parseNumber(String numberAsText); |
Use Case: JSON Serialization
This would be particularly useful in cases like *JSON serialization
in REST APIs (Using Jackson <https://github.com/FasterXML/jackson>)*,
where number types are often altered during
serialization/deserialization. Consider the following test case:
|@Test void testNumberMemoryUsage() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper(); Map<String, Object>
numbersObject = Map.of("aShort", (short) 1234, "aFloat", (float)
1.33); final String jsonText =
mapper.writeValueAsString(numbersObject); Map<String, Object>
parsedJsonObject = mapper.readValue(jsonText, new TypeReference<>()
{}); // Expected: Short.class | Actual: Integer.class
assertEquals(Short.class, parsedJsonObject.get("aShort").getClass());
// Expected: Float.class | Actual: Double.class
assertEquals(Float.class, parsedJsonObject.get("aFloat").getClass()); } |
Reference Implementation
Here’s a rough implementation to illustrate the idea:
|private static Number parseNumber(final String numberStr) { try { if
(numberStr.contains(".")) { double doubleValue =
Double.parseDouble(numberStr); return (doubleValue >=
-Float.MAX_VALUE && doubleValue <= Float.MAX_VALUE) ? (float)
doubleValue : doubleValue; } else { long longValue =
Long.parseLong(numberStr); if (longValue >= Byte.MIN_VALUE &&
longValue <= Byte.MAX_VALUE) { return (byte) longValue; } else if
(longValue >= Short.MIN_VALUE && longValue <= Short.MAX_VALUE) {
return (short) longValue; } else if (longValue >= Integer.MIN_VALUE
&& longValue <= Integer.MAX_VALUE) { return (int) longValue; } else {
return longValue; } } } catch (NumberFormatException e) { return
parseBigNumber(numberStr); } } private static Number
parseBigNumber(final String numberStr) { try { return new
BigInteger(numberStr); // Try BigInteger first } catch
(NumberFormatException e) { // Only create BigDecimal if BigInteger
fails BigDecimal bd = new BigDecimal(numberStr); try { // Convert to
BigInteger if there's no fraction return bd.toBigIntegerExact(); }
catch (ArithmeticException ex) { return bd; // If it's a decimal,
return BigDecimal } } } |
Would love to hear your thoughts on this proposal. Appreciate your
feedback and guidance!
Thanks & Regards,
Sathish Kumar Thiyagarajan