From 67d579a7e62d672997b6001475bdea20645b3387 Mon Sep 17 00:00:00 2001 From: Looly Date: Thu, 22 Jan 2026 00:57:48 +0800 Subject: [PATCH] add NumberFormatUtil --- .../hutool/v7/core/math/NumberFormatUtil.java | 162 ++++++++++++++++++ .../cn/hutool/v7/core/math/NumberParser.java | 67 +++----- .../hutool/v7/core/convert/Issue3105Test.java | 5 +- .../v7/core/convert/IssueIALV38Test.java | 9 +- .../hutool/v7/core/math/NumberParserTest.java | 5 +- .../hutool/v7/core/math/NumberUtilTest.java | 106 ++++++------ 6 files changed, 247 insertions(+), 107 deletions(-) create mode 100644 hutool-core/src/main/java/cn/hutool/v7/core/math/NumberFormatUtil.java diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/math/NumberFormatUtil.java b/hutool-core/src/main/java/cn/hutool/v7/core/math/NumberFormatUtil.java new file mode 100644 index 0000000000..2f8a2304c0 --- /dev/null +++ b/hutool-core/src/main/java/cn/hutool/v7/core/math/NumberFormatUtil.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2026 Hutool Team. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package cn.hutool.v7.core.math; + +import cn.hutool.v7.core.convert.ConvertUtil; +import cn.hutool.v7.core.text.StrUtil; +import cn.hutool.v7.core.util.ObjUtil; + +import java.math.BigDecimal; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.text.ParsePosition; +import java.util.Locale; + +/** + * 基于NumberFormat封装的数字格式化/解析工具类 + * 提供常用的数字格式化、字符串解析为数字的方法,包含异常处理和参数校验 + * + * @author Looly + * @since 7.0.0 + */ +public class NumberFormatUtil { + + /** + * 默认区域 + */ + private static final Locale DEFAULT_LOCALE = Locale.getDefault(Locale.Category.FORMAT); + + // region ----- format + + /** + * 使用默认区域(Locale.getDefault(Locale.Category.FORMAT))格式化数字 + * + * @param number 要格式化的数字(支持Number子类:Integer/Long/Double/BigDecimal等) + * @return 格式化后的字符串,null返回空字符串 + */ + public static String format(final Number number) { + return format(number, DEFAULT_LOCALE); + } + + /** + * 指定区域格式化数字 + * + * @param number 要格式化的数字 + * @param locale 区域(如Locale.US、Locale.CHINA) + * @return 格式化后的字符串,null返回空字符串 + */ + public static String format(final Number number, final Locale locale) { + if (number == null) { + return ""; + } + final NumberFormat nf = NumberFormat.getInstance(locale); + return nf.format(number); + } + + /** + * 格式化数字并指定小数位数 + * + * @param number 要格式化的数字 + * @param fractionDigits 小数位数(>=0) + * @return 格式化后的字符串 + */ + public static String format(final Number number, final int fractionDigits) { + return format(number, fractionDigits, Locale.getDefault()); + } + + /** + * 指定区域和小数位数格式化数字 + * + * @param number 要格式化的数字 + * @param fractionDigits 小数位数(>=0) + * @param locale 区域 + * @return 格式化后的字符串 + */ + public static String format(final Number number, final int fractionDigits, final Locale locale) { + if (number == null) { + return ""; + } + if (fractionDigits < 0) { + throw new IllegalArgumentException("fractionDigits must be >=0:" + fractionDigits); + } + final NumberFormat nf = NumberFormat.getInstance(locale); + nf.setMaximumFractionDigits(fractionDigits); + nf.setMinimumFractionDigits(fractionDigits); + return nf.format(number); + } + // endregion + + // region ----- parse + + /** + * 使用默认区域解析字符串为数字(返回BigDecimal,避免精度丢失) + * + * @param source 要解析的字符串(如"1,234.56"、"1234.56") + * @return 解析后的BigDecimal,解析失败返回null + */ + public static Number parse(final String source) { + return parse(source, DEFAULT_LOCALE); + } + + /** + * 指定区域解析字符串为数字 + * + * @param source 要解析的字符串 + * @param locale 区域(解析时匹配对应格式,如Locale.US解析"1,234.56") + * @return 解析后的BigDecimal,解析失败返回null + */ + public static Number parse(String source, final Locale locale) { + // 参数校验 + source = StrUtil.trim( source); + if(StrUtil.isEmpty(source)){ + return null; + } + + // issue#I79VS7 去除头部加号 + source = StrUtil.removeAllPrefix(source, "+"); + + // issue@4197@Github 转为半角 + source = ConvertUtil.toDBC(source); + + // issue#IDJ1NS@Gitee 处理科学计数法E+格式 + // NumberFormat对E+格式支持不佳,使用BigDecimal直接解析 + if (StrUtil.containsIgnoreCase(source, "e")) { + try { + return new BigDecimal(source); + } catch (final NumberFormatException e) { + // BigDecimal解析失败,继续使用NumberFormat尝试 + } + } + + final NumberFormat nf = NumberFormat.getInstance(ObjUtil.defaultIfNull(locale, DEFAULT_LOCALE)); + if (nf instanceof DecimalFormat) { + // issue#1818@Github + // 当字符串数字超出double的长度时,会导致截断,此处使用BigDecimal接收 + ((DecimalFormat) nf).setParseBigDecimal(true); + } + + final ParsePosition pos = new ParsePosition(0); + final Number result = nf.parse(source, pos); + + // 校验解析是否完全成功(pos.getIndex()等于字符串长度才是完全解析) + if (result == null || pos.getIndex() != source.length()) { + throw new NumberFormatException("Unparseable number: [" + source + "] at: " + pos.getIndex()); + } + return result; + } + // endregion +} diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/math/NumberParser.java b/hutool-core/src/main/java/cn/hutool/v7/core/math/NumberParser.java index 6fd832d386..d39eba2146 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/math/NumberParser.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/math/NumberParser.java @@ -17,11 +17,9 @@ package cn.hutool.v7.core.math; import cn.hutool.v7.core.array.ArrayUtil; -import cn.hutool.v7.core.convert.ConvertUtil; import cn.hutool.v7.core.text.CharUtil; import cn.hutool.v7.core.text.StrUtil; -import java.math.BigDecimal; import java.math.BigInteger; import java.text.DecimalFormat; import java.text.NumberFormat; @@ -212,7 +210,9 @@ public class NumberParser { * @param numberStr 数字字符串 * @return long */ - public long parseLong(final String numberStr) { + public long parseLong(String numberStr) { + // 去除类型标记 + numberStr = StrUtil.removeSuffixIgnoreCase(numberStr, "L"); if (isBlankOrNaN(numberStr)) { return 0; } @@ -243,7 +243,9 @@ public class NumberParser { * @return long * @since 5.5.5 */ - public float parseFloat(final String numberStr) { + public float parseFloat(String numberStr) { + // 去除类型标记 + numberStr = StrUtil.removeSuffixIgnoreCase(numberStr, "F"); if (isBlankOrNaN(numberStr)) { return 0; } @@ -269,7 +271,9 @@ public class NumberParser { * @param numberStr 数字字符串 * @return double */ - public double parseDouble(final String numberStr) { + public double parseDouble(String numberStr) { + // 去除类型标记 + numberStr = StrUtil.removeSuffixIgnoreCase(numberStr, "D"); if (isBlankOrNaN(numberStr)) { return 0; } @@ -347,13 +351,20 @@ public class NumberParser { return 0; } - // 16进制 + // 16进制,需要在结尾标识解析前判断16进制,如0xFF表示16进制数,末尾的F并不能标识类型 if (StrUtil.startWithIgnoreCase(numberStr, "0x")) { - // 0x04表示16进制数 - return Long.parseLong(numberStr.substring(2), 16); + return parseLong(numberStr); } - return doParse(numberStr); + // 以特殊字母结尾的数字,按照其对应类型解析返回 + final char lastChar = Character.toUpperCase(numberStr.charAt(numberStr.length() - 1)); + return switch (lastChar) { + case 'F' -> parseFloat(numberStr); + case 'D' -> parseDouble(numberStr); + case 'L' -> parseLong(numberStr); + default -> doParse(numberStr); + }; + } /** @@ -362,42 +373,8 @@ public class NumberParser { * * @return 数字 */ - private Number doParse(String numberStr) { - Locale locale = this.locale; - if (null == locale) { - locale = Locale.getDefault(Locale.Category.FORMAT); - } - if (StrUtil.startWith(numberStr, CharUtil.PLUS)) { - // issue#I79VS7 - numberStr = StrUtil.subSuf(numberStr, 1); - } - - // issue@4197@Github 转为半角 - numberStr = ConvertUtil.toDBC(numberStr); - - // issue#IDJ1NS@Gitee 处理科学计数法E+格式 - // NumberFormat对E+格式支持不佳,使用BigDecimal直接解析 - if (StrUtil.containsIgnoreCase(numberStr, "e")) { - try { - return new BigDecimal(numberStr); - } catch (final NumberFormatException e) { - // BigDecimal解析失败,继续使用NumberFormat尝试 - } - } - - try { - final NumberFormat format = NumberFormat.getInstance(locale); - if (format instanceof DecimalFormat) { - // issue#1818@Github - // 当字符串数字超出double的长度时,会导致截断,此处使用BigDecimal接收 - ((DecimalFormat) format).setParseBigDecimal(true); - } - return format.parse(numberStr); - } catch (final ParseException e) { - final NumberFormatException nfe = new NumberFormatException(e.getMessage()); - nfe.initCause(e); - throw nfe; - } + private Number doParse(final String numberStr) { + return NumberFormatUtil.parse(numberStr, this.locale); } /** diff --git a/hutool-core/src/test/java/cn/hutool/v7/core/convert/Issue3105Test.java b/hutool-core/src/test/java/cn/hutool/v7/core/convert/Issue3105Test.java index 59fe2872c1..705e2ed7cd 100644 --- a/hutool-core/src/test/java/cn/hutool/v7/core/convert/Issue3105Test.java +++ b/hutool-core/src/test/java/cn/hutool/v7/core/convert/Issue3105Test.java @@ -16,9 +16,10 @@ package cn.hutool.v7.core.convert; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertNull; + /** * https://github.com/chinabugotech/hutool/issues/3105 */ @@ -26,6 +27,6 @@ public class Issue3105Test { @Test void toLongTest() { final Long aLong = ConvertUtil.toLong("0.a"); - Assertions.assertEquals(0L, aLong); + assertNull(aLong); } } diff --git a/hutool-core/src/test/java/cn/hutool/v7/core/convert/IssueIALV38Test.java b/hutool-core/src/test/java/cn/hutool/v7/core/convert/IssueIALV38Test.java index 42deabb0be..c5169211cc 100644 --- a/hutool-core/src/test/java/cn/hutool/v7/core/convert/IssueIALV38Test.java +++ b/hutool-core/src/test/java/cn/hutool/v7/core/convert/IssueIALV38Test.java @@ -22,9 +22,12 @@ import org.junit.jupiter.api.Test; import java.math.BigDecimal; public class IssueIALV38Test { + + /** + * V7版本变更,旧版本不会抛出异常,新版本中无法解析非正常数字 + */ @Test - void name() { - final Object o = ConvertUtil.convertWithCheck(BigDecimal.class, " 111啊", null, false); - Assertions.assertEquals(new BigDecimal("111"), o); + void convertWithCheckTest() { + Assertions.assertThrows(NumberFormatException.class, ()-> ConvertUtil.convertWithCheck(BigDecimal.class, " 111啊", null, false)); } } diff --git a/hutool-core/src/test/java/cn/hutool/v7/core/math/NumberParserTest.java b/hutool-core/src/test/java/cn/hutool/v7/core/math/NumberParserTest.java index ca0ff1a3f2..c579e4c473 100644 --- a/hutool-core/src/test/java/cn/hutool/v7/core/math/NumberParserTest.java +++ b/hutool-core/src/test/java/cn/hutool/v7/core/math/NumberParserTest.java @@ -16,7 +16,6 @@ package cn.hutool.v7.core.math; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -25,8 +24,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows; public class NumberParserTest { @Test void parseLongTest() { - final long value = NumberParser.INSTANCE.parseLong("0.a"); - Assertions.assertEquals(0L, value); + // 0.a是非法数字,抛出NumberFormatException + assertThrows(NumberFormatException.class, () -> NumberParser.INSTANCE.parseLong("0.a")); } @Test diff --git a/hutool-core/src/test/java/cn/hutool/v7/core/math/NumberUtilTest.java b/hutool-core/src/test/java/cn/hutool/v7/core/math/NumberUtilTest.java index dea7c5eb8a..9aa580ce85 100644 --- a/hutool-core/src/test/java/cn/hutool/v7/core/math/NumberUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/v7/core/math/NumberUtilTest.java @@ -108,14 +108,14 @@ public class NumberUtilTest { @Test public void isIntegerTest() { final String[] validNumArr = {"0", "-0", "+0", "12", "+12", "1234567890", "2147483647", "-2147483648", - "0x012345678", "0X012345678", "0xabcdef", "-0xabcdef", "0x12abcdef", "0x7FFFFFFF", "-0x80000000", - "01234567", "017777777777", "-020000000000" + "0x012345678", "0X012345678", "0xabcdef", "-0xabcdef", "0x12abcdef", "0x7FFFFFFF", "-0x80000000", + "01234567", "017777777777", "-020000000000" }; privateIsIntegerTest(validNumArr, true); final String[] invalidNumArr = {null, "", " ", "+", "+1.", ".1", "99L", "99D", "99F", "12.3", "123e1", "-12.3", "1.2.3", - "2147483648", "0x80000000", "020000000000", "-2147483649", "-0x80000001", "-020000000001", "-020000000001", - "a", "+a", "123abc", "09" + "2147483648", "0x80000000", "020000000000", "-2147483649", "-0x80000001", "-020000000001", "-020000000001", + "a", "+a", "123abc", "09" }; privateIsIntegerTest(invalidNumArr, false); } @@ -129,20 +129,20 @@ public class NumberUtilTest { @Test public void isLongTest() { final String[] validNumArr = { - "0", "0L", "-0L", "+0L", "12", "+12", "1234567890123456789", "99L", - "2147483648", "0x80000000", "020000000000", "-2147483649", "-0x80000001", "-020000000001", "-020000000001", - "9223372036854775807", "-9223372036854775808", - "0x0123456789", "0X0123456789", "0x123456789abcdef", "0xabcdef123456789", "0x7FFFFFFF", "-0x80000000", - "0x7fffffffffffffff", "-0x8000000000000000", - "01234567", "0777777777777777777777", "-01000000000000000000000" + "0", "0L", "-0L", "+0L", "12", "+12", "1234567890123456789", "99L", + "2147483648", "0x80000000", "020000000000", "-2147483649", "-0x80000001", "-020000000001", "-020000000001", + "9223372036854775807", "-9223372036854775808", + "0x0123456789", "0X0123456789", "0x123456789abcdef", "0xabcdef123456789", "0x7FFFFFFF", "-0x80000000", + "0x7fffffffffffffff", "-0x8000000000000000", + "01234567", "0777777777777777777777", "-01000000000000000000000" }; privateIsLongTest(validNumArr, true); final String[] invalidNumArr = {null, "", " ", "+", "+1.", ".1", "99D", "99F", "12.3", "123e1", "-12.3", "1.2.3", - "a", "+a", "123abc", "09", - "9223372036854775808", "-9223372036854775809", - "0x8000000000000000", "-0x8000000000000001", - "01000000000000000000000", "-01000000000000000000001" + "a", "+a", "123abc", "09", + "9223372036854775808", "-9223372036854775809", + "0x8000000000000000", "-0x8000000000000001", + "01000000000000000000000", "-01000000000000000000001" }; privateIsLongTest(invalidNumArr, false); } @@ -322,7 +322,7 @@ public class NumberUtilTest { @Test public void decimalFormatNaNTest() { - assertThrows(IllegalArgumentException.class, ()->{ + assertThrows(IllegalArgumentException.class, () -> { final Double a = 0D; final Double b = 0D; @@ -333,7 +333,7 @@ public class NumberUtilTest { @Test public void decimalFormatNaNTest2() { - assertThrows(IllegalArgumentException.class, ()->{ + assertThrows(IllegalArgumentException.class, () -> { final Double a = 0D; final Double b = 0D; @@ -384,21 +384,20 @@ public class NumberUtilTest { } @Test - void emptyToBigDecimalTest(){ - assertThrows(IllegalArgumentException.class,()-> NumberUtil.toBigDecimal("")); + void emptyToBigDecimalTest() { + assertThrows(IllegalArgumentException.class, () -> NumberUtil.toBigDecimal("")); } @Test - void naNToBigDecimalTest(){ + void naNToBigDecimalTest() { assertEquals(BigDecimal.ZERO, NumberUtil.toBigDecimal("NaN")); } @Test public void issue2878Test() throws ParseException { // https://github.com/chinabugotech/hutool/issues/2878 - // 当数字中包含一些非数字字符时,按照JDK的规则,不做修改。 - final BigDecimal bigDecimal = NumberUtil.toBigDecimal("345.sdf"); - assertEquals(NumberFormat.getInstance().parse("345.sdf"), bigDecimal.longValue()); + // 当数字中包含一些非数字字符时,V7版本中抛出异常 + assertThrows(NumberFormatException.class, () -> NumberUtil.toBigDecimal("345.sdf")); } @Test @@ -419,20 +418,18 @@ public class NumberUtilTest { number = NumberUtil.parseInt(" "); assertEquals(0, number); - number = NumberUtil.parseInt("10F"); - assertEquals(10, number); - - number = NumberUtil.parseInt("22.4D"); - assertEquals(22, number); - - number = NumberUtil.parseInt("22.6D"); - assertEquals(22, number); + // 浮点数解析为int时会造成精度丢失 + assertThrows(NumberFormatException.class, () -> { + NumberUtil.parseInt("22.4D"); + }); number = NumberUtil.parseInt("0"); assertEquals(0, number); number = NumberUtil.parseInt(".123"); assertEquals(0, number); + number = NumberUtil.parseInt(".999"); + assertEquals(0, number); } @Test @@ -445,7 +442,7 @@ public class NumberUtilTest { @Test public void parseIntTest3() { - assertThrows(NumberFormatException.class, ()->{ + assertThrows(NumberFormatException.class, () -> { final int v1 = NumberUtil.parseInt("d"); assertEquals(0, v1); }); @@ -453,7 +450,7 @@ public class NumberUtilTest { @Test public void parseIntTest4() { - assertThrows(NumberFormatException.class, ()->{ + assertThrows(NumberFormatException.class, () -> { // issue#I5M55F // 科学计数法忽略支持,科学计数法一般用于表示非常小和非常大的数字,这类数字转换为int后精度丢失,没有意义。 final String numberStr = "429900013E20220812163344551"; @@ -471,9 +468,7 @@ public class NumberUtilTest { assertEquals(456, NumberUtil.parseInt("abc", 456)); // -------------------------- Parse success ----------------------- - - assertEquals(123, NumberUtil.parseInt("123.abc", 789)); - + assertEquals(789, NumberUtil.parseInt("123.abc", 789)); assertEquals(123, NumberUtil.parseInt("123.3", null)); } @@ -506,7 +501,7 @@ public class NumberUtilTest { } @Test - public void parseNumberTest3(){ + public void parseNumberTest3() { // -------------------------- Parse failed ----------------------- @@ -520,16 +515,16 @@ public class NumberUtilTest { // -------------------------- Parse success ----------------------- - assertEquals(123, NumberUtil.parseNumber("123.abc", 789).intValue()); + assertEquals(789, NumberUtil.parseNumber("123.abc", 789).intValue()); assertEquals(123.3D, NumberUtil.parseNumber("123.3", (Number) null).doubleValue()); - assertEquals(0.123D, NumberUtil.parseNumber("0.123.3", (Number) null).doubleValue()); + assertNull(NumberUtil.parseNumber("0.123.3", (Number) null)); } @Test - void issueIDJ1NSTest(){ + void issueIDJ1NSTest() { final String numberstr1 = "8.37095942E+9"; final BigDecimal result1 = (BigDecimal) NumberUtil.parseNumber(numberstr1); final String numberstr2 = "8.37095942e+9"; @@ -567,14 +562,15 @@ public class NumberUtilTest { number = NumberUtil.parseLong(" "); assertEquals(0, number); - number = NumberUtil.parseLong("10F"); - assertEquals(10, number); + // 明确float类型时,解析long报错,避免精度丢失问题 + assertThrows(NumberFormatException.class, () -> { + NumberUtil.parseLong("10F"); + }); - number = NumberUtil.parseLong("22.4D"); - assertEquals(22, number); - - number = NumberUtil.parseLong("22.6D"); - assertEquals(22, number); + // 明确double类型时,解析long报错,避免精度丢失问题 + assertThrows(NumberFormatException.class, () -> { + NumberUtil.parseLong("22.4D"); + }); number = NumberUtil.parseLong("0"); assertEquals(0, number); @@ -702,11 +698,11 @@ public class NumberUtilTest { @Test public void rangeMinTest() { - assertThrows(NegativeArraySizeException.class, ()-> NumberUtil.range(0, Integer.MIN_VALUE)); + assertThrows(NegativeArraySizeException.class, () -> NumberUtil.range(0, Integer.MIN_VALUE)); } @Test - public void isPrimeTest(){ + public void isPrimeTest() { assertTrue(NumberUtil.isPrime(2)); assertTrue(NumberUtil.isPrime(3)); assertTrue(NumberUtil.isPrime(7)); @@ -718,6 +714,7 @@ public class NumberUtilTest { assertFalse(NumberUtil.isPrime(296733)); assertFalse(NumberUtil.isPrime(20_4123_2399)); } + @Test public void isPrimeTest2() { assertTrue(NumberUtil.isPrime(2)); @@ -743,14 +740,15 @@ public class NumberUtilTest { assertNull(NumberUtil.parseFloat("abc", null)); assertNull(NumberUtil.parseFloat("a123.33", null)); + assertNull(NumberUtil.parseFloat("123.33a", null)); assertNull(NumberUtil.parseFloat("..123", null)); + assertEquals(1233F, NumberUtil.parseFloat(StrUtil.EMPTY, 1233F)); // -------------------------- Parse success ----------------------- - assertEquals(123.33F, NumberUtil.parseFloat("123.33a", null)); assertEquals(0.123F, NumberUtil.parseFloat(".123", null)); @@ -766,9 +764,9 @@ public class NumberUtilTest { assertNull(NumberUtil.parseDouble("..123", null)); assertEquals(1233D, NumberUtil.parseDouble(StrUtil.EMPTY, 1233D)); + assertThrows(NumberFormatException.class, () -> NumberUtil.parseDouble("123.33a")); // -------------------------- Parse success ----------------------- - assertEquals(123.33D, NumberUtil.parseDouble("123.33a", null)); assertEquals(0.123D, NumberUtil.parseDouble(".123", null)); } @@ -798,10 +796,10 @@ public class NumberUtilTest { @Test void nullToZeroTest() { - assertEquals(0, NumberUtil.nullToZero((Integer)null)); - assertEquals(0L, NumberUtil.nullToZero((Long)null)); - assertEquals(0D, NumberUtil.nullToZero((Double)null)); - assertEquals(0D, NumberUtil.nullToZero((Double)null)); + assertEquals(0, NumberUtil.nullToZero((Integer) null)); + assertEquals(0L, NumberUtil.nullToZero((Long) null)); + assertEquals(0D, NumberUtil.nullToZero((Double) null)); + assertEquals(0D, NumberUtil.nullToZero((Double) null)); assertEquals(0F, NumberUtil.nullToZero((Float) null)); assertEquals(0, NumberUtil.nullToZero((Short) null)); assertEquals(0, NumberUtil.nullToZero((Byte) null));