前面介绍了字符串变量的四种赋值方式,对于简单的赋值来说完全够用了,即便是两个字符串拼接,也只需通过加号把两个目标串连起来即可。但对于复杂的赋值来说就麻烦了,假设现在需要拼接一个很长的字符串,字符串内部包含了各种类型的变量,有整型,有双精度型,有布尔型,有字符型,中间还夹杂着一些起粘合作用的子串,如此一来只能使劲地填写加号,把各种变量努力加加加加上去,就像有时打印日志调用System.out.println就非常痛苦,加号多到让你眼花缭乱。
为了不让加号如此横行霸道,String类型从Java5开始,额外提供了format方法对填入字符串的各种变量进行格式化。具体地说,是在一个模板字符串中填写类似“%s”、“%d”、“%f”这样的记号先占几个位置,然后给format方法的输入参数分别指定对应位置的变量名称,表示这些变量值依次替换模板中的“%s”、“%d”、“%f”等等记号。以上模板串用到的占位记号也叫做格式转换符,分别说明如下:
%s : 这是字符串的占位记号,可原样展示字符串如"Hello"。
%c : 这是字符的占位记号,可原样展示字符如'A'。
%b : 这是布尔值的占位记号,可原样展示true或者false。
%d : 这是十进制整数(含字节型、短整型、整型、长整型)的占位记号,可原样展示十进制数如255。
%o : 这是八进制整数的占位记号,填写十进制数,格式化后会转换成八进制数。例如,输入整数255会输出八进制数377。
%x : 这是十六进制整数的占位记号,填写十进制数,格式化后会转换成十六进制数。例如,输入整数255会输出十六进制数ff。
%f : 这是浮点数的占位记号,格式化后会转换成七位小数(整数部分与小数部分加起来)。
下面是利用format方法格式化单个变量值与多个变量值的代码例子:

		// 往字符串填入另一个字符串
String fromString = String.format("格式化子串的字符串:%s", "Hello");
System.out.println("fromString="+fromString);
// 往字符串填入字符
String fromChar = String.format("格式化字符的字符串:%s", 'A');
System.out.println("fromChar="+fromChar);
// 往字符串填入布尔值
String fromBoolean = String.format("格式化布尔值的字符串:%b", false);
System.out.println("fromBoolean="+fromBoolean);
// 往字符串填入十进制整数
String fromInt = String.format("格式化整型数的字符串:%d", 255);
System.out.println("fromInt="+fromInt);
// 往字符串填入十六进制数
String fromOct = String.format("格式化十六进制数的字符串:%o", 255);
System.out.println("fromOct="+fromOct);
// 往字符串填入八进制数
String fromHex = String.format("格式化八进制数的字符串:%x", 255);
System.out.println("fromHex="+fromHex);
// 往字符串填入浮点数
String fromFloat = String.format("格式化浮点数的字符串:%f", 3.14);
System.out.println("fromFloat="+fromFloat);
// 格式化字符串的时候,同时填充多个变量
String manyVariable = String.format("以下字符串包括了多个变量值:%s,%c,%b,%d,%o,%x,%f",
"Hello", 'A', false, 255, 255, 255, 3.14);
System.out.println("manyVariable="+manyVariable);

观察上面的代码,可见大部分的基本类型都支持格式化,除了双精度型。如果双精度数的精度刚好在浮点数范围之内,还能借助标记%f来格式化,要是双精度数超过了浮点数的精度,还能使用%f格式化吗?接下来通过以下的测试代码,看看3.1415926这个双精度数会被%f格式化成什么样子:

		// 注意,双精度数若是通过%f格式化双精度数,则会强制转成浮点数
String fromDouble = String.format("双精度数格式化后丢失精度的字符串:%f", 3.1415926);
System.out.println("fromDouble="+fromDouble);

运行以上的测试代码,打印的日志结果如下所示:

fromDouble=双精度数格式化后丢失精度的字符串:3.141593

可见使用%f格式化双精度数,超出范围的小数部分被强行四舍五入了,因而%f并不适合用于直接格式化双精度型。若想让双精度数在格式化时不损失精度,需要程序员指定小数点后面的保留位数,比如%.8f表示格式化时保留八位小数部分,f前面的数字越大代表保留的位数越多,双精度数的数值精度就越高。利用%.8f改写之前的双精度数格式化代码,改写后的演示代码如下:

		// 因此,格式化双精度数之时,需要指定小数点后面的保留位数
String fromDecimal = String.format("格式化双精度数的字符串:%.8f", 3.1415926);
System.out.println("fromDecimal="+fromDecimal);

运行如上的演示代码,程序运行结果如下所示:

fromDecimal=格式化双精度数的字符串:3.14159260

从日志信息可见,此时双精度数的小数部分得以完整地保存了下来。

所谓的格式化,不单单是按照标记填写具体数值,还要求字符串格式整齐划一。譬如统计世界各国人口,列表中的各国人口数值应当右对齐,这样谁多谁少方能一目了然。既然要求支持对齐,那么得先明确该列数字的最大位数,之后才能在位数范围内选择左对齐还是右对齐。整数部分最大位数的标记方式与小数部分的保留位数类似,唯一的区别是整数位数的标记不加点号,而小数位数的标记要加点号,例如%8d表示待格式化的整数将占据八个字符空间,并且默认右对齐、左补空格。倘若要求左对齐,则格式化标记需添加符号,像%-8d表示待格式化的整数在八位空间内左对齐,并且右补空格。有时候数字代表一串编码,即使未达到最大位数也得在左边补0,此时格式化标记要在位数前面补充0,代表空出来的位置填0而不是填空格,如标记%08d表示待格式化的整数要求右对齐、左补0。下面是对整数位数进行各种格式化的代码例子:

		// 对整数分配固定长度,该整数默认右对齐、左补空格
String fromLenth = String.format("格式化固定长度(默认右对齐)的整数字符串:(%8d)", 255);
System.out.println("fromLenth="+fromLenth);
// 对整数分配固定长度,且该整数左对齐、右补空格
String fromLeft = String.format("格式化固定长度且左对齐的整数字符串:(%-8d)", 255);
System.out.println("fromLeft="+fromLeft);
// 对整数分配固定长度,该整数默认右对齐、左补0
String fromZero = String.format("格式化固定长度且左补0的整数字符串:(%08d)", 255);
System.out.println("fromZero="+fromZero);

运行上述的格式化代码,得到下列的日志打印结果:

fromLenth=格式化固定长度(默认右对齐)的整数字符串:(     255)
fromLeft=格式化固定长度且左对齐的整数字符串:(255 )
fromZero=格式化固定长度且左补0的整数字符串:(00000255)

由此可见,格式化后的数字既实现了右对齐,也实现了左对齐,还支持在空位补0。

一旦格式化用得多了,便会出现某个变量需要多次填入的情况,比如说“重要的事情说三遍”,后面的句子就得输入三次,像以下代码所示的那样,“别迟到”三字反复写了三次:

		// 字符串格式化的时候,可能出现某个变量被多次填入的情况
String fromRepeat1 = String.format("重要的事情说三遍:%s,%s,%s", "别迟到", "别迟到", "别迟到");
System.out.println("fromRepeat1="+fromRepeat1);

这种做法无疑非常拖沓,不但写起来费劲,看起来也费神。为此格式化又设计了形如“%n$s”的标记,其中n表示当前标记取的是第几个参数值,尾巴的s就是普通的格式化标记,中间的美元符号$把两者隔开。例如标记%1$s表示当前要取第一个参数,且该参数类型为字符串,于是前述的“重要的事情说三遍”即可简化为以下代码:

		// 重复填入某个变量值,可利用“%数字$”的形式,其中“数字$”表示这里取后面的第几个变量值
String fromRepeat2 = String.format("重要的事情说三遍:%1$s,%1$s,%1$s", "别迟到");
System.out.println("fromRepeat2="+fromRepeat2);

  

现在有个比较常见的业务要求,金额数字通常都要保留小数点后面两位,像余额宝的每日收益就精确到小数点后两位的单位分。此时采取标记%.2f即可实现要求,但是余额宝内部对账可不能仅仅保留两位小数,一般至少保留小数点后三位的单位厘,那么对账用的格式化标记就变成了%.3f。这样有的场合要求更高精度,有的场合精度要求不高,意味着标记%.nf中间的n值是随时变化着的。若要处理变化的输入数值,必须通过方法实现相关功能,也就是需要设计一个新方法,该方法的输入参数包括待格式化的数字,以及需要保留的小数位数,方法的返回值为截取指定小数位的字符串。
对于双精度数字来说,此时要先根据小数位数构建一个形如%.nf的格式化标记串,再依据该标记格式化最终的数值字符串。由于百分号%是格式化的保留字符,因此要用两个百分号%%来表达一个百分符号%,于是双精度数的小数位数格式化代码书写如下:

	// 对双精度类型的变量截取小数位,多余部分的数字默认四舍五入
public static String formatWithDouble(double value, int digit) {
// 先根据小数位数构建格式化标记串。两个百分号%%可转义为一个百分符号%
String format = String.format("%%.%df", digit);
// 再依据该标记对具体数字进行字符串格式化
String result = String.format(format, value);
return result;
}

对于大小数类型而言,BigDecimal提供了专门的setScale方法,该方法不但允许指定截取的小数位,还支持设置特定的舍入规则,当然通常情况使用RoundingMode.HALF_UP代表四舍五入即可。下面便是截取大小数的方法代码例子:

	// 对大小数类型的变量截取小数位,可指定多余部分数字的舍入规则
public static String formatWithBigDecimal(BigDecimal value, int digit) {
// 大小数类型的setScale方法需要指定明确的舍入规则,其中HALF_UP表示四舍五入
BigDecimal result = value.setScale(digit, RoundingMode.HALF_UP);
return result.toString();
}

接下来外部分别调用上面的双精度数格式化方法formatWithDouble,以及大小数格式化方法formatWithBigDecimal,具体的测试调用代码如下所示:

		double normalDecimal = 19.895;
// 保留双精度数的小数点后面两位
String normalResult = formatWithDouble(normalDecimal, 2);
System.out.println("normalResult="+normalResult);
BigDecimal bigDecimal = new BigDecimal("123456789012345678.901");
// 保留大小数的小数点后面两位
String bigResult = formatWithBigDecimal(bigDecimal, 2);
System.out.println("bigResult="+bigResult);

运行上述的精度格式化代码,输出以下的日志打印信息:

normalResult=19.90
bigResult=123456789012345678.90

可见不管是双精度格式化,还是大小数格式化,都实现了四舍五入保留两位小数的目标。

更多Java技术文章参见《Java开发笔记(序)章节目录

Java开发笔记(三十五)字符串格式化的更多相关文章

  1. Java开发学习(三十五)----SpringBoot快速入门及起步依赖解析

    一.SpringBoot简介 SpringBoot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化 Spring 应用的初始搭建以及开发过程. 使用了 Spring 框架后已经简化了我 ...

  2. Java开发笔记(十五)短路逻辑运算的优势

    前面提到逻辑运算只能操作布尔变量,这其实是不严谨的,因为经过Java编程实现,会发现“&”.“|”.“^”这几个逻辑符号竟然可以对数字进行运算.譬如下面的代码就直接对数字分别开展了“与”.“或 ...

  3. Java开发学习(三十六)----SpringBoot三种配置文件解析

    一. 配置文件格式 我们现在启动服务器默认的端口号是 8080,访问路径可以书写为 http://localhost:8080/books/1 在线上环境我们还是希望将端口号改为 80,这样在访问的时 ...

  4. “全栈2019”Java多线程第三十五章:如何获取线程被等待的时间?

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  5. Java开发笔记(一百五十)C3P0连接池的用法

    JDBC既制定统一标准兼容了多种数据库,又利用预报告堵上了SQL注入漏洞,照理说已经很完善了,可是人算不如天算,它在性能方面不尽如人意.问题出在数据库连接的管理上,按照正常流程,每次操作完数据库,都要 ...

  6. Java开发笔记(九十五)NIO配套的文件工具Files

    NIO不但引进了高效的文件通道,而且新增了更加好用的文件工具家族,包括路径组工具Paths.路径工具Path.文件组工具Files.先看路径组工具Paths,该工具提供了静态方法get,输入某个文件的 ...

  7. 程序员与年龄:四十岁普通开发、三十五岁首席架构、三十岁基层Leader

    最近,有一个词儿特别热门--躺平.有没有人跟你说过:"躺平说起来容易,做起来更容易." 和躺平相对的是另外一个词--内卷,群聊的时候,已经很多次看过草卷起来了.jpg表情包.某些节 ...

  8. Java开发笔记(一百五十一)Druid连接池的用法

    C3P0连接池自诞生以来在Java Web领域反响甚好,业已成为hibenate框架推荐的连接池.谁知人红是非多,C3P0在大型应用场合中暴露了越来越多的局限性,包括但不限于下列几点:1.C3P0管理 ...

  9. Java开发学习(二十五)----使用PostMan完成不同类型参数传递

    一.请求参数 请求路径设置好后,只要确保页面发送请求地址和后台Controller类中配置的路径一致,就可以接收到前端的请求,接收到请求后,如何接收页面传递的参数? 关于请求参数的传递与接收是和请求方 ...

  10. Java基础(三十五)Math、Random类和数字格式化(String.format方法)

    一.Math类 Math类常用的方法: public static long abs (double a) 返回a的绝对值 public static double max (double a,dou ...

随机推荐

  1. CentOS 编译安装 Nodejs (实测 笔记 Centos 7.3 + node 6.9.5)

    环境: 系统硬件:vmware vsphere (CPU:2*4核,内存2G,双网卡) 系统版本:CentOS-7.0-1406-x86_64-DVD.iso 安装步骤: 1.准备 1.1 显示系统版 ...

  2. laravel 目录权限

    chown -R www:www /data/wwwroot   #变更目录所有者并向下传递 find /data/wwwroot/ -type d -exec chmod 755 {} \;   # ...

  3. Java作业六(2017-10-30)

    /*游戏引擎包,播放音乐*/ import com.rupeng.game.GameCore; public class Mc implements Runnable{ public static v ...

  4. APP研发录笔记

    一.消灭全局变量 在内存不足时,系统会回收一部分闲置的资源,由于App被切换到后台,所以之前存放的全局变量很容易被回收,这时再切换到前台继续使用,会报空指针崩溃.想彻底解决这个问题,就要使用序列化. ...

  5. PuppeteerSharp+AngleSharp的爬虫实战之汽车之家数据抓取

    参考了DotNetSpider示例, 感觉DotNetSpider太重了,它是一个比较完整的爬虫框架. 对比了以下各种无头浏览器,最终采用PuppeteerSharp+AngleSharp写一个爬虫示 ...

  6. Ansible批量修改root密码

    0x01:首先做好免密登录 http://www.cnblogs.com/evlon/p/8094306.html 0x02:批量修改密码 ansible all -m raw -a "ec ...

  7. python3 stack/ queue和deque模块

    '''栈stack 先进后出FILO (first in last out)'''lst = []lst.append("张一山")lst.append("杨紫" ...

  8. 版本号严格遵守semver语义化标准

    地址:http://semver.org/lang/zh-CN/?spm=a219a.7629140.0.0.GUJMXE 语义化版本 2.0.0 摘要 版本格式:主版本号.次版本号.修订号,版本号递 ...

  9. SQL基本注入演示

    作者:ZERO 所属团队:Arctic Shell 参考文献:<sql注入攻击与防御> 使用平台:pikachu漏洞练习平台 导语:  在owasp发布的top10排行榜中注入漏洞一直是危 ...

  10. python—day9 函数的定义、操作使用方法、函数的分类、函数的嵌套调用

    一.函数的定义 函数的四个组成部分: 函数名. 函数体. 函数返回值. 函数参数 1.概念:重复利用的工具,可以完成特定功能的代码块,函数是存放代码块的容器 2.定义: def:声明函数的关键词 函数 ...