java %0d,我如何使java.text.NumberFormat格式0.0d为“0”而不是“+0”?
针对Java数值格式化中零值不显示正号的需求,采用ChoiceFormat与DecimalFormat组合:ChoiceFormat将0映射为空、正数映射为“+”,DecimalFormat处理小数位与负号,实现零显示“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与正数,是一个非常巧妙的技巧。
AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。
AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。
AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。
Fuzor Windows版是一套面向建筑、工程与施工团队的BIM/VDC平台,可汇集多来源模型和进度数据,完成实时可视化、4D施工推演、场地物流规划、问题检查、成果演示及团队协同。
Gety Windows版是一款本地AI文件搜索工具,可索引电脑中的文档和图片,通过全文搜索、语义检索与OCR快速定位内容,并提供原版式预览、筛选和AI工具连接功能。
iMazing Windows版是一款面向iPhone、iPad和iPod用户的本地设备管理工具,可在电脑上完成多版本备份、照片与音乐传输、信息导出、应用数据管理以及新旧设备迁移。













