@@ -588,6 +588,50 @@ public double getDouble(String key) throws JSONException {
588588 }
589589 }
590590
591+ /**
592+ * Get the float value associated with a key.
593+ *
594+ * @param key
595+ * A key string.
596+ * @return The numeric value.
597+ * @throws JSONException
598+ * if the key is not found or if the value is not a Number
599+ * object and cannot be converted to a number.
600+ */
601+ public float getFloat (String key ) throws JSONException {
602+ Object object = this .get (key );
603+ try {
604+ return object instanceof Number ? ((Number ) object ).floatValue ()
605+ : Float .parseFloat (object .toString ());
606+ } catch (Exception e ) {
607+ throw new JSONException ("JSONObject[" + quote (key )
608+ + "] is not a number." , e );
609+ }
610+ }
611+
612+ /**
613+ * Get the Number value associated with a key.
614+ *
615+ * @param key
616+ * A key string.
617+ * @return The numeric value.
618+ * @throws JSONException
619+ * if the key is not found or if the value is not a Number
620+ * object and cannot be converted to a number.
621+ */
622+ public Number getNumber (String key ) throws JSONException {
623+ Object object = this .get (key );
624+ try {
625+ if (object instanceof Number ) {
626+ return (Number )object ;
627+ }
628+ return stringToNumber (object .toString ());
629+ } catch (Exception e ) {
630+ throw new JSONException ("JSONObject[" + quote (key )
631+ + "] is not a number." , e );
632+ }
633+ }
634+
591635 /**
592636 * Get the int value associated with a key.
593637 *
@@ -1267,51 +1311,14 @@ public Number optNumber(String key, Number defaultValue) {
12671311
12681312 if (val instanceof String ) {
12691313 try {
1270- // decimal representation
1271- if (((String )val ).indexOf ('.' )>=0 || ((String )val ).indexOf ('e' )>=0 || ((String )val ).indexOf ('E' )>=0 ) {
1272- // quick dirty way to see if we need a BigDecimal instead of a Double
1273- if (((String )val ).length ()>14 ) {
1274- return new BigDecimal ((String )val );
1275- }
1276- return Double .valueOf ((String )val );
1277- }
1278- // integer representation.
1279- // This will narrow any values to the smallest reasonable Object representation
1280- // (Integer, Long, or BigInteger)
1281- // The compare string length method reduces GC,
1282- // but leads to smaller integers being placed in larger wrappers even though not
1283- // needed. i.e. 1,000,000,000 -> Long even though it's an Integer
1284- // 1,000,000,000,000,000,000 -> BigInteger even though it's a Long
1285-
1286- // string version
1287- if (((String )val ).length ()<=9 ){
1288- return Integer .valueOf ((String )val );
1289- }
1290- if (((String )val ).length ()<=18 ){
1291- return Long .valueOf ((String )val );
1292- }
1293- return new BigInteger ((String )val );
1294-
1295- // BigInteger version: We use a similar bitLenth compare as
1296- // BigInteger#intValueExact uses. Increases GC, but objects hold
1297- // only what they need. i.e. Less runtime overhead if the value is
1298- // long lived. Which is the better tradeoff?
1299-
1300- //BigInteger bi = new BigInteger((String)val);
1301- //if(bi.bitLength()<=31){
1302- // return Integer.valueOf(bi.intValue());
1303- //}
1304- //if(bi.bitLength()<=63){
1305- // return Long.valueOf(bi.longValue());
1306- //}
1307- //return bi;
1314+ return stringToNumber ((String ) val );
13081315 } catch (Exception e ) {
13091316 return defaultValue ;
13101317 }
13111318 }
13121319 return defaultValue ;
13131320 }
1314-
1321+
13151322 /**
13161323 * Get an optional string associated with a key. It returns an empty string
13171324 * if there is no such key. If the value is not a string and is not null,
@@ -1757,6 +1764,65 @@ public boolean similar(Object other) {
17571764 }
17581765 }
17591766
1767+ /**
1768+ * Converts a string to a number using the narrowest possible type. Possible
1769+ * returns for this function are BigDecimal, Double, BigInteger, Long, and Integer.
1770+ *
1771+ * An Exception is thrown if
1772+ *
1773+ * @param val value to convert
1774+ * @return Number representation of the value.
1775+ * @throws NumberFormatException thrown if the value is not a valid number. A public
1776+ * caller should catch this and wrap it in a {@link JSONException} if applicable.
1777+ */
1778+ protected static Number stringToNumber (final String val ) throws NumberFormatException {
1779+ char initial = val .charAt (0 );
1780+ if ((initial >= '0' && initial <= '9' ) || initial == '-' ) {
1781+ // decimal representation
1782+ if (val .indexOf ('.' ) > -1 || val .indexOf ('e' ) > -1
1783+ || val .indexOf ('E' ) > -1
1784+ || "-0" .equals (val )) {
1785+ // quick dirty way to see if we need a BigDecimal instead of a Double
1786+ if (val .length ()>14 ) {
1787+ return new BigDecimal (val );
1788+ }
1789+ return Double .valueOf (val );
1790+ }
1791+ // integer representation.
1792+ // This will narrow any values to the smallest reasonable Object representation
1793+ // (Integer, Long, or BigInteger)
1794+ // The compare string length method reduces GC,
1795+ // but leads to smaller integers being placed in larger wrappers even though not
1796+ // needed. i.e. 1,000,000,000 -> Long even though it's an Integer
1797+ // 1,000,000,000,000,000,000 -> BigInteger even though it's a Long
1798+
1799+ // string version
1800+ if (val .length ()<=9 ){
1801+ return Integer .valueOf (val );
1802+ }
1803+ if (val .length ()<=18 ){
1804+ return Long .valueOf (val );
1805+ }
1806+ return new BigInteger (val );
1807+
1808+ // BigInteger version: We use a similar bitLenth compare as
1809+ // BigInteger#intValueExact uses. Increases GC, but objects hold
1810+ // only what they need. i.e. Less runtime overhead if the value is
1811+ // long lived. Which is the better tradeoff? This is closer to what's
1812+ // in stringToValue.
1813+
1814+ //BigInteger bi = new BigInteger((String)val);
1815+ //if(bi.bitLength()<=31){
1816+ // return Integer.valueOf(bi.intValue());
1817+ //}
1818+ //if(bi.bitLength()<=63){
1819+ // return Long.valueOf(bi.longValue());
1820+ //}
1821+ //return bi;
1822+ }
1823+ throw new NumberFormatException ("val [" +val +"] is not a valid number." );
1824+ }
1825+
17601826 /**
17611827 * Try to convert a string into a number, boolean, or null. If the string
17621828 * can't be converted, return the string.
0 commit comments