From af6aba957f4dc4d19d5f295172b4ddc941ca1681 Mon Sep 17 00:00:00 2001 From: Stephen Colebourne Date: Sun, 20 Jul 2003 16:03:21 +0000 Subject: [PATCH] Update null handling behaviour and documentation bug 21734, from Phil Steiz git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@137476 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/commons/lang/math/NumberUtils.java | 175 +++++++++++------- .../commons/lang/math/NumberUtilsTest.java | 64 ++++++- 2 files changed, 165 insertions(+), 74 deletions(-) diff --git a/src/java/org/apache/commons/lang/math/NumberUtils.java b/src/java/org/apache/commons/lang/math/NumberUtils.java index 2df7357aa..302674fcd 100644 --- a/src/java/org/apache/commons/lang/math/NumberUtils.java +++ b/src/java/org/apache/commons/lang/math/NumberUtils.java @@ -69,7 +69,7 @@ import org.apache.commons.lang.NullArgumentException; * @author Phil Steitz * @author Matthew Hawthorne * @since 2.0 - * @version $Id: NumberUtils.java,v 1.3 2003/07/14 22:25:05 bayard Exp $ + * @version $Id: NumberUtils.java,v 1.4 2003/07/20 16:03:21 scolebourne Exp $ */ public final class NumberUtils { @@ -124,8 +124,10 @@ public final class NumberUtils { /** *

Convert a String to an int, returning * zero if the conversion fails.

+ * + *

If the string is null, zero is returned.

* - * @param str the string to convert + * @param str the string to convert, may be null * @return the int represented by the string, or zero if * conversion fails */ @@ -136,8 +138,10 @@ public final class NumberUtils { /** *

Convert a String to an int, returning a * default value if the conversion fails.

+ * + *

If the string is null, the default value is returned.

* - * @param str the string to convert + * @param str the string to convert, may be null * @param defaultValue the default value * @return the int represented by the string, or the default if conversion fails */ @@ -190,8 +194,8 @@ public final class NumberUtils { * *

First, the value is examined for a type qualifier on the end * ('f','F','d','D','l','L'). If it is found, it starts - * trying to create succissively larger types from the type specified - * until one is found that can hold the value.

+ * trying to create successively larger types from the type specified + * until one is found that can represent the value.

* *

If a type specifier is not found, it will check for a decimal point * and then try successively larger types from Integer to @@ -202,61 +206,66 @@ public final class NumberUtils { * will be interpreted as a hexadecimal integer. Values with leading * 0's will not be interpreted as octal.

* - * @param val String containing a number + *

Returns null if the string is null.

+ * + *

This method does not trim the input string, i.e., strings with leading + * or trailing spaces will generate NumberFormatExceptions.

+ * + * @param str String containing a number, may be null * @return Number created from the string * @throws NumberFormatException if the value cannot be converted */ - public static Number createNumber(String val) throws NumberFormatException { - if (val == null) { + public static Number createNumber(String str) throws NumberFormatException { + if (str == null) { return null; } - if (val.length() == 0) { + if (str.length() == 0) { throw new NumberFormatException("\"\" is not a valid number."); } - if (val.startsWith("--")) { + if (str.startsWith("--")) { // this is protection for poorness in java.lang.BigDecimal. // it accepts this as a legal value, but it does not appear // to be in specification of class. OS X Java parses it to // a wrong value. return null; } - if (val.startsWith("0x") || val.startsWith("-0x")) { - return createInteger(val); + if (str.startsWith("0x") || str.startsWith("-0x")) { + return createInteger(str); } - char lastChar = val.charAt(val.length() - 1); + char lastChar = str.charAt(str.length() - 1); String mant; String dec; String exp; - int decPos = val.indexOf('.'); - int expPos = val.indexOf('e') + val.indexOf('E') + 1; + int decPos = str.indexOf('.'); + int expPos = str.indexOf('e') + str.indexOf('E') + 1; if (decPos > -1) { if (expPos > -1) { if (expPos < decPos) { - throw new NumberFormatException(val + " is not a valid number."); + throw new NumberFormatException(str + " is not a valid number."); } - dec = val.substring(decPos + 1, expPos); + dec = str.substring(decPos + 1, expPos); } else { - dec = val.substring(decPos + 1); + dec = str.substring(decPos + 1); } - mant = val.substring(0, decPos); + mant = str.substring(0, decPos); } else { if (expPos > -1) { - mant = val.substring(0, expPos); + mant = str.substring(0, expPos); } else { - mant = val; + mant = str; } dec = null; } if (!Character.isDigit(lastChar)) { - if (expPos > -1 && expPos < val.length() - 1) { - exp = val.substring(expPos + 1, val.length() - 1); + if (expPos > -1 && expPos < str.length() - 1) { + exp = str.substring(expPos + 1, str.length() - 1); } else { exp = null; } //Requesting a specific type.. - String numeric = val.substring(0, val.length() - 1); + String numeric = str.substring(0, str.length() - 1); boolean allZeros = isAllZeros(mant) && isAllZeros(exp); switch (lastChar) { case 'l' : @@ -273,7 +282,7 @@ public final class NumberUtils { return createBigInteger(numeric); } - throw new NumberFormatException(val + " is not a valid number."); + throw new NumberFormatException(str + " is not a valid number."); case 'f' : case 'F' : try { @@ -302,48 +311,48 @@ public final class NumberUtils { } //Fall through default : - throw new NumberFormatException(val + " is not a valid number."); + throw new NumberFormatException(str + " is not a valid number."); } } else { //User doesn't have a preference on the return type, so let's start //small and go from there... - if (expPos > -1 && expPos < val.length() - 1) { - exp = val.substring(expPos + 1, val.length()); + if (expPos > -1 && expPos < str.length() - 1) { + exp = str.substring(expPos + 1, str.length()); } else { exp = null; } if (dec == null && exp == null) { //Must be an int,long,bigint try { - return createInteger(val); + return createInteger(str); } catch (NumberFormatException nfe) { } try { - return createLong(val); + return createLong(str); } catch (NumberFormatException nfe) { } - return createBigInteger(val); + return createBigInteger(str); } else { //Must be a float,double,BigDec boolean allZeros = isAllZeros(mant) && isAllZeros(exp); try { - Float f = createFloat(val); + Float f = createFloat(str); if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) { return f; } } catch (NumberFormatException nfe) { } try { - Double d = createDouble(val); + Double d = createDouble(str); if (!(d.isInfinite() || (d.doubleValue() == 0.0D && !allZeros))) { return d; } } catch (NumberFormatException nfe) { } - return createBigDecimal(val); + return createBigDecimal(str); } } @@ -354,89 +363,119 @@ public final class NumberUtils { * *

Returns true if s is null.

* - * @param s the String to check + * @param str the String to check * @return if it is all zeros or null */ - private static boolean isAllZeros(String s) { - if (s == null) { + private static boolean isAllZeros(String str) { + if (str == null) { return true; } - for (int i = s.length() - 1; i >= 0; i--) { - if (s.charAt(i) != '0') { + for (int i = str.length() - 1; i >= 0; i--) { + if (str.charAt(i) != '0') { return false; } } - return s.length() > 0; + return str.length() > 0; } //----------------------------------------------------------------------- /** *

Convert a String to a Float.

+ * + *

Returns null if the string is null.

* - * @param val a String to convert + * @param str a String to convert, may be null * @return converted Float * @throws NumberFormatException if the value cannot be converted */ - public static Float createFloat(String val) { - return Float.valueOf(val); + public static Float createFloat(String str) { + if (str == null) { + return null; + } + return Float.valueOf(str); } /** *

Convert a String to a Double.

* - * @param val a String to convert + *

Returns null if the string is null.

+ * + * @param str a String to convert, may be null * @return converted Double * @throws NumberFormatException if the value cannot be converted */ - public static Double createDouble(String val) { - return Double.valueOf(val); + public static Double createDouble(String str) { + if (str == null) { + return null; + } + return Double.valueOf(str); } /** *

Convert a String to a Integer, handling * hex and octal notations.

+ * + *

Returns null if the string is null.

* - * @param val a String to convert + * @param str a String to convert, may be null * @return converted Integer * @throws NumberFormatException if the value cannot be converted */ - public static Integer createInteger(String val) { + public static Integer createInteger(String str) { // decode() handles 0xAABD and 0777 (hex and octal) as well. - return Integer.decode(val); + if (str == null) { + return null; + } + return Integer.decode(str); } /** *

Convert a String to a Long.

* - * @param val a String to convert + *

Returns null if the string is null.

+ * + * @param str a String to convert, may be null * @return converted Long * @throws NumberFormatException if the value cannot be converted */ - public static Long createLong(String val) { - return Long.valueOf(val); + public static Long createLong(String str) { + if (str == null) { + return null; + } + return Long.valueOf(str); } /** *

Convert a String to a BigInteger.

+ * + *

Returns null if the string is null.

* - * @param val a String to convert + * @param str a String to convert, may be null * @return converted BigInteger * @throws NumberFormatException if the value cannot be converted */ - public static BigInteger createBigInteger(String val) { - BigInteger bi = new BigInteger(val); + public static BigInteger createBigInteger(String str) { + if (str == null) { + return null; + } + BigInteger bi = new BigInteger(str); return bi; } /** *

Convert a String to a BigDecimal.

* - * @param val a String to convert + *

Returns null if the string is null.

+ * + * @param str a String to convert, may be null * @return converted BigDecimal * @throws NumberFormatException if the value cannot be converted */ - public static BigDecimal createBigDecimal(String val) { - BigDecimal bd = new BigDecimal(val); + public static BigDecimal createBigDecimal(String str) { + if (str == null) { + return null; + } + BigDecimal bd = new BigDecimal(str); return bd; } @@ -445,7 +484,7 @@ public final class NumberUtils { /** *

Returns the minimum value in an array.

* - * @param array an array + * @param array an array, must not be null or empty * @return the minimum value in the array * @throws NullArgumentException if array is null * @throws IllegalArgumentException if array is empty @@ -472,7 +511,7 @@ public final class NumberUtils { /** *

Returns the minimum value in an array.

* - * @param array an array + * @param array an array, must not be null or empty * @return the minimum value in the array * @throws NullArgumentException if array is null * @throws IllegalArgumentException if array is empty @@ -499,7 +538,7 @@ public final class NumberUtils { /** *

Returns the minimum value in an array.

* - * @param array an array + * @param array an array, must not be null or empty * @return the minimum value in the array * @throws NullArgumentException if array is null * @throws IllegalArgumentException if array is empty @@ -526,7 +565,7 @@ public final class NumberUtils { /** *

Returns the minimum value in an array.

* - * @param array an array + * @param array an array, must not be null or empty * @return the minimum value in the array * @throws NullArgumentException if array is null * @throws IllegalArgumentException if array is empty @@ -553,7 +592,7 @@ public final class NumberUtils { /** *

Returns the minimum value in an array.

* - * @param array an array + * @param array an array, must not be null or empty * @return the minimum value in the array * @throws NullArgumentException if array is null * @throws IllegalArgumentException if array is empty @@ -582,7 +621,7 @@ public final class NumberUtils { /** *

Returns the maximum value in an array.

* - * @param array an array + * @param array an array, must not be null or empty * @return the minimum value in the array * @throws NullArgumentException if array is null * @throws IllegalArgumentException if array is empty @@ -609,7 +648,7 @@ public final class NumberUtils { /** *

Returns the maximum value in an array.

* - * @param array an array + * @param array an array, must not be null or empty * @return the minimum value in the array * @throws NullArgumentException if array is null * @throws IllegalArgumentException if array is empty @@ -636,7 +675,7 @@ public final class NumberUtils { /** *

Returns the maximum value in an array.

* - * @param array an array + * @param array an array, must not be null or empty * @return the minimum value in the array * @throws NullArgumentException if array is null * @throws IllegalArgumentException if array is empty @@ -663,7 +702,7 @@ public final class NumberUtils { /** *

Returns the maximum value in an array.

* - * @param array an array + * @param array an array, must not be null or empty * @return the minimum value in the array * @throws NullArgumentException if array is null * @throws IllegalArgumentException if array is empty @@ -690,7 +729,7 @@ public final class NumberUtils { /** *

Returns the maximum value in an array.

* - * @param array an array + * @param array an array, must not be null or empty * @return the minimum value in the array * @throws NullArgumentException if array is null * @throws IllegalArgumentException if array is empty diff --git a/src/test/org/apache/commons/lang/math/NumberUtilsTest.java b/src/test/org/apache/commons/lang/math/NumberUtilsTest.java index dfa4397ce..646340b32 100644 --- a/src/test/org/apache/commons/lang/math/NumberUtilsTest.java +++ b/src/test/org/apache/commons/lang/math/NumberUtilsTest.java @@ -72,7 +72,7 @@ import org.apache.commons.lang.SystemUtils; * @author Phil Steitz * @author Stephen Colebourne * @author Matthew Hawthorne - * @version $Id: NumberUtilsTest.java,v 1.2 2003/06/28 18:42:04 scolebourne Exp $ + * @version $Id: NumberUtilsTest.java,v 1.3 2003/07/20 16:03:21 scolebourne Exp $ */ public class NumberUtilsTest extends TestCase { @@ -98,6 +98,8 @@ public class NumberUtilsTest extends TestCase { public void testStringToIntString() { assertTrue("stringToInt(String) 1 failed", NumberUtils.stringToInt("12345") == 12345); assertTrue("stringToInt(String) 2 failed", NumberUtils.stringToInt("abc") == 0); + assertTrue("stringToInt(empty) failed", NumberUtils.stringToInt("") == 0); + assertTrue("stringToInt(null) failed", NumberUtils.stringToInt(null) == 0); } /** @@ -124,7 +126,8 @@ public class NumberUtilsTest extends TestCase { assertEquals("createNumber(String) 12 failed", new Float("1.1E20"), NumberUtils.createNumber("1.1E20")); assertEquals("createNumber(String) 13 failed", new Double("-1.1E200"), NumberUtils.createNumber("-1.1E200")); assertEquals("createNumber(String) 14 failed", new Double("1.1E-200"), NumberUtils.createNumber("1.1E-200")); - + assertEquals("createNumber(null) failed", null, NumberUtils.createNumber(null)); + // jdk 1.2 doesn't support this. unsure about jdk 1.2.2 if(SystemUtils.isJavaVersionAtLeast(1.3f)) { assertEquals("createNumber(String) 15 failed", new BigDecimal("1.1E-700"), NumberUtils.createNumber("1.1E-700F")); @@ -146,26 +149,68 @@ public class NumberUtilsTest extends TestCase { public void testCreateFloat() { assertEquals("createFloat(String) failed", new Float("1234.5"), NumberUtils.createFloat("1234.5")); + assertEquals("createFloat(null) failed", null, NumberUtils.createFloat(null)); + try { + Float f = NumberUtils.createFloat(""); + fail("createFloat(empty) failed"); + } catch (NumberFormatException ex) { + ; + } } public void testCreateDouble() { assertEquals("createDouble(String) failed", new Double("1234.5"), NumberUtils.createDouble("1234.5")); + assertEquals("createDouble(null) failed", null, NumberUtils.createDouble(null)); + try { + Double d = NumberUtils.createDouble(""); + fail("createDouble(empty) failed"); + } catch (NumberFormatException ex) { + ; + } } public void testCreateInteger() { assertEquals("createInteger(String) failed", new Integer("12345"), NumberUtils.createInteger("12345")); + assertEquals("createInteger(null) failed", null, NumberUtils.createInteger(null)); + try { + Integer i = NumberUtils.createInteger(""); + fail("createInteger(empty) failed"); + } catch (NumberFormatException ex) { + ; + } } public void testCreateLong() { - assertEquals("createInteger(String) failed", new Long("12345"), NumberUtils.createLong("12345")); + assertEquals("createLong(String) failed", new Long("12345"), NumberUtils.createLong("12345")); + assertEquals("createLong(null) failed", null, NumberUtils.createLong(null)); + try { + Long l = NumberUtils.createLong(""); + fail("createLong(empty) failed"); + } catch (NumberFormatException ex) { + ; + } } public void testCreateBigInteger() { assertEquals("createBigInteger(String) failed", new BigInteger("12345"), NumberUtils.createBigInteger("12345")); + assertEquals("createBigInteger(null) failed", null, NumberUtils.createBigInteger(null)); + try { + BigInteger i = NumberUtils.createBigInteger(""); + fail("createBigInteger(empty) failed"); + } catch (NumberFormatException ex) { + ; + } } public void testCreateBigDecimal() { assertEquals("createBigDecimal(String) failed", new BigDecimal("1234.5"), NumberUtils.createBigDecimal("1234.5")); + assertEquals("createBigDecimal(null) failed", null, NumberUtils.createBigDecimal(null)); + try { + BigDecimal d = NumberUtils.createBigDecimal(""); + fail("createBigDecimal(empty) failed"); + } catch (NumberFormatException ex) { + ; + } } // min/max tests @@ -855,6 +900,15 @@ public class NumberUtilsTest extends TestCase { val = "11d11"; assertTrue("isNumber(String) 21 Neg failed", !NumberUtils.isNumber(val)); assertTrue("isNumber(String)/createNumber(String) 21 Neg failed", !checkCreateNumber(val)); + val = "11 11"; + assertTrue("isNumber(String) 22 Neg failed", !NumberUtils.isNumber(val)); + assertTrue("isNumber(String)/createNumber(String) 22 Neg failed", !checkCreateNumber(val)); + val = " 1111"; + assertTrue("isNumber(String) 23 Neg failed", !NumberUtils.isNumber(val)); + assertTrue("isNumber(String)/createNumber(String) 23 Neg failed", !checkCreateNumber(val)); + val = "1111 "; + assertTrue("isNumber(String) 24 Neg failed", !NumberUtils.isNumber(val)); + assertTrue("isNumber(String)/createNumber(String) 24 Neg failed", !checkCreateNumber(val)); } @@ -867,9 +921,7 @@ public class NumberUtilsTest extends TestCase { return true; } catch (NumberFormatException e) { return false; - } catch (NullPointerException e) { - return false; - } + } } public void testConstants() {