发布于2026-07-16 阅读(0)
扫一扫,手机访问
在Ja va的数值格式化中,有时会遇到一个看似简单却很棘手的需求:既要显示正负号,又希望零值不带符号,直接显示为“0”。比如:-123.45 → “-123.45”,123.45 → “+123.45”,而0.0则要输出为“0”。
如果直接用DecimalFormat的setPositivePrefix("+"),你会发现0也会被格式化为“+0”——这显然不是我们想要的。那么,如何优雅地解决这个问题?
这里可以借助ChoiceFormat来动态选择前缀。思路是:当数值为0时,不加任何前缀;当数值大于0时,加上“+”;负数则沿用默认的“-”。下面是一个完整的实现示例:
import static org.junit.Assert.assertEquals;
import ja va.text.ChoiceFormat;
import ja va.text.DecimalFormat;
import ja va.text.FieldPosition;
import ja va.text.NumberFormat;
import ja va.text.ParsePosition;
import org.junit.Test;
public class NumberFormatTest {
@Test
public void testNumberFormat() {
NumberFormat nf = new MyNumberFormat();
assertEquals("-1234.4", nf.format(-1234.4));
assertEquals("0.0", nf.format(0));
assertEquals("+0.3", nf.format(0.3));
assertEquals("+12.0", nf.format(12));
}
}
class MyNumberFormat extends NumberFormat {
private DecimalFormat df = new DecimalFormat("0.0#");
private ChoiceFormat cf = new ChoiceFormat(
new double[] { 0.0, ChoiceFormat.nextDouble(0.0) },
new String[] { "", "+" });
@Override
public StringBuffer format(double number, StringBuffer toAppendTo,
FieldPosition pos) {
return toAppendTo.append(cf.format(number)).append(df.format(number));
}
@Override
public StringBuffer format(long number, StringBuffer toAppendTo,
FieldPosition pos) {
return toAppendTo.append(cf.format(number)).append(df.format(number));
}
@Override
public Number parse(String source, ParsePosition parsePosition) {
throw new UnsupportedOperationException();
}
}
DecimalFormat的模式字符串实际上包含正负两个子模式,负子模式是可选的。如果只写"0.0#",等价于"0.0#;-0.0#",也就是说对负数会自动加上“-”。所以直接使用DecimalFormat,是无法区分“0”和“正数”的——它们都会共用正子模式,而正子模式默认没有“+”。
那么,如何给正数加上“+”?答案是利用ChoiceFormat来做一个分段映射:
[0.0, ChoiceFormat.nextDouble(0.0)) 区间时,对应空字符串 ""。细心的读者会注意到,ChoiceFormat.nextDouble(0.0) 是大于0的最小浮点数,所以这个区间实际上只包含0.0本身。ChoiceFormat.nextDouble(0.0) 时,对应 "+"。这就覆盖了所有正数。DecimalFormat自带的负子模式处理就好,ChoiceFormat对负数会返回空字符串(因为负无穷到0不在上述两个区间内,默认取第一个或最后一个索引),不会干扰负号。换句话说,ChoiceFormat负责决定是否加上“+”前缀,而DecimalFormat负责处理数值的小数位数和负号。两者组合,正好实现了“零无符号、正数带+、负数带-”的效果。
如果对ChoiceFormat的边界行为有疑问,可以查阅文档:它的限制数组必须升序排列,未命中时会自动取最接近的边界。这里用ChoiceFormat.nextDouble(0.0)可以精确区分0与正数,是一个非常巧妙的技巧。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8