Skip to content

Commit

Permalink
Improved Long-Double Number Policy (#2674)
Browse files Browse the repository at this point in the history
* Improved Long-Double Number Policy

The Parsing of a Double value was always executing a `Long.parseLong(value)`, which generated a `NumberFormatException`.

Identifying that a Number is a Double or a Long can be easily achieve (in a naive way) looking for the decimal separator.

This simple change avoids the extra `NumberFormatException`

A simple JUnit test, parsing a `Long` or a `Double` 10K times shows the next values:

* Double (old parsing): ~42 ms
* Double (new parsing): ~6 ms
* Long (old parsing): ~7 ms
* Long (new parsing): ~7 ms

As we can see, the parsing for `Long` values stays the same (±1ms), while the parsing for `Double` is dramatically improved.

Reducing the number of exceptions also has a positive side effect in memory consumption.

* Replace `contains(".")` by `indexOf('.') >= 0`

The usage of `indexOf(char)` is slightly faster

* Rename exception variables
  • Loading branch information
ctasada authored May 18, 2024
1 parent 570d911 commit 454a491
Showing 1 changed file with 20 additions and 12 deletions.
32 changes: 20 additions & 12 deletions gson/src/main/java/com/google/gson/ToNumberPolicy.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,30 @@ public Number readNumber(JsonReader in) throws IOException {
@Override
public Number readNumber(JsonReader in) throws IOException, JsonParseException {
String value = in.nextString();
try {
return Long.parseLong(value);
} catch (NumberFormatException longE) {
if (value.indexOf('.') >= 0) {
return parseAsDouble(value, in);
} else {
try {
Double d = Double.valueOf(value);
if ((d.isInfinite() || d.isNaN()) && !in.isLenient()) {
throw new MalformedJsonException(
"JSON forbids NaN and infinities: " + d + "; at path " + in.getPreviousPath());
}
return d;
} catch (NumberFormatException doubleE) {
throw new JsonParseException(
"Cannot parse " + value + "; at path " + in.getPreviousPath(), doubleE);
return Long.parseLong(value);
} catch (NumberFormatException e) {
return parseAsDouble(value, in);
}
}
}

private Number parseAsDouble(String value, JsonReader in) throws IOException {
try {
Double d = Double.valueOf(value);
if ((d.isInfinite() || d.isNaN()) && !in.isLenient()) {
throw new MalformedJsonException(
"JSON forbids NaN and infinities: " + d + "; at path " + in.getPreviousPath());
}
return d;
} catch (NumberFormatException e) {
throw new JsonParseException(
"Cannot parse " + value + "; at path " + in.getPreviousPath(), e);
}
}
},

/**
Expand Down

0 comments on commit 454a491

Please sign in to comment.