java.util工具类之Formatter类
1 Formatter 类
Java能对创建格式化输出进行支持的核心在于Formatter类。该类提供了格式转换功能,从而可以采用我们所喜欢的各种方式显示数字、字符串以及时间和日期。操作方式与C/C++的printf()函数类似。该类还进一步简化了从C/C++代码到Java代码的转换。
1.1 Formatter 类的构造函数
在使用Formatter格式化输出之前,必须创建Formatter对象。通常,Formatter通过将程序使用的二进制形式转换成格式化的文本进行工作。在缓冲区中存储格式化文本,无论何时需要,都可以通过程序获取缓冲区中的内容。可以让Formatter自动提供这个缓冲区,也可以在创建Formatter对象时显式提供。让Formatter将自己的缓冲区输出到文件中也是有可能的。
Formatter类定义了许多构造函数,从而可以使用各种方式构造Formatter对象。下面是其中的一些构造函数:
Formatter()
Formatter(Appendable buf)
Formatter(Appendable buf,Locale loc)
Formatter(String filename) throws FileNotFoundException
Formatter(String fileName,String charset) throws FileNotFoundException,UnsupportedEncodingException
Formatter(File outF)throws FileNotFoundException
Formatter(OutputStream outStrm)
其中,buf指定了用于保存格式化输出缓冲区,如果buf为null,Formatter将自动分配StringBuilder以保存格式化输出。参数loc指定了地区。如果没有指定地区,就使用默认地区。参数filename指定了将用于接收格式化输出的文件的名称。参数charset指定了字符集。如果没有指定字符集,就使用默认字符集。参数outF指定了一个引用,这个引用指向将用于接收输出的已打来的文件。参数outStrm也指定一个引用,这个引用指向将用于接收输出的输出流。如果使用文件,那么输出也可以写入文件中。
使用最广泛的构造函数可能是第一个,它没有参数。这个构造函数自动使用默认地区。并自动分配StringBuilder以保存格式化输出。
1.2 Formatter 类的方法
表1显示了Formatter类定义的方法。
方 法 | 描 述 |
---|---|
void close() | 关闭调用Formatter对象。这会导致Formatter对象使用的所有资源被释放。Formatter对象在关闭之后,将不能再使用。如果试图使用已关闭的Formatter对象。会导致FormatterClosedException异常 |
void flush() | 刷新格式化缓冲区。这会导致将缓冲区中当前的所有输出都写入目标中。该方法主要用于文件绑定的Formatter对象 |
Formatter format(String fmtString,Object … args) | 根据fmtString中包含的格式说明符,格式化args传递过来的参数。返回调用对象 |
Formatter format(Locale loc,String fmtString,Object … args) | 根据fmtString中包含的格式说明符,格式化args传递过来的参数,为格式化操作使用loc指定的地区。返回调用对象 |
IOExceotion ioException() | 如果作为目标的底层对象抛出IOException异常,就返回该异常;否则返回null |
Locale locale() | 返回调用对象的地区 |
Appendable out() | 返回指向底层对象的引用,底层对象是输出的目标 |
String toString() | 返回包含格式化输出的String对象 |
1.3 格式化的基础知识
在创建完Formatter对象之后,就可以使用Formatter对象创建格式化字符串了。为此,使用format()方法。该方法最常用的版本如下所示:
Formatter format(String fmtString,Object ... args)
fmtString包含两种类型的条目:第一种类型是由将被简单地复制到输出缓冲区中的字符构成的;第二种类型包含格式说明符,格式说明符定义了显示后续参数的方式。
格式说明符最简单的形式是以百分号开头,后面跟随格式转换说明符。所有格式转换说明符都由单个字符构成。例如,用于浮点数的格式说明符是%f。通常,参数的数量必须与格式说明符的数量相等,并且格式说明符与参数按照从左向右的顺序进行匹配。例如,分析下面的代码段:
Formatter fmt = new Formatter();
fmt.format("Formatting %s is easy %d %f","with Java",10,98.6);
这个代码段创建了一个包含以下字符串的Formatter对象:
Formatting with Java is easy 10 98.600000
在这个例子中,格式说明符%s、%d和%f被格式字符串后面的参数替换。因此,%s被"with Java"替换,%d被10替换,%f被98.6替换。所有其他字符简单地保持不变。格式说明符%s指定一个字符串,%d指定一个整数,%f指定一个浮点值。
format()方法能够接收的格式说明符相等广泛,在表1中显示了这些格式书名副。注意许多说明符具有大写和小写两种形式。当时用大写说明符时,字母以大写显示。除此之外,大写和小写说明符执行相同的转换。Java根据对应的参数来检查每个格式说明符的类型。如果参数不匹配,会抛出IllegalFormatException异常。
格式说明符 | 适用的转换 | 格式说明符 | 适用的转换 |
---|---|---|---|
%a %A | 浮点型十六进制值 | %g %G | 基于被格式化的值和精度使用%c或%f |
%b %B | 布尔型 | %o | 八进制整数 |
%c | 字符 | %n | 插入一个换行符 |
%d | 十进制整数 | %s %S | 字符串 |
%h %H | 参数的哈希码 | %t %T | 时间和日期 |
%c %E | 科学计数法 | %x %X | 十六进制整数 |
%f | 十进制浮点数 | %% | 插入一个%符号 |
一旦拥有格式化的字符串,就可以通过调用toString()方法来获取。例如,继续前面的例子,下面的语句获取fmt中包含的格式化字符串:
String str = fmt.toString();
当然,如果只是希望显示格式化字符串,那么没有必要首先将字符串赋给String对象。例如,当将Formatter对象传递给println()方法时,会自动调用Formatter对象的toStirng()方法。
下面的简短程序将所有这些内容放到一起,该程序显示了如何创建和显示格式化字符串:
//A very simple example that uses Formatter.
import java.util.Formatter;
class FormatDemo {
public static void main(String[] args) {
Formatter fmt = new Formatter();
fmt.format("Formatting %s is easy %d %f","with Java",10,98.6);
System.out.println(fmt);
fmt.close();
/**
* 输出:
* Formatting with Java is easy 10 98.600000
*/
}
}
另外一点:通过调用out()方法可以获取对底层输出缓冲区的引用。该方法返回一个指向Appendable对象的引用。
现在我们已经知道用于创建格式化字符串的一般机制,接下来将详细讨论每种转换,另外还将描述各种选项,例如对其、最小字段宽度以及精度。
1.4 格式化字符串和字符
为了格式化单个字符,可以使用%c,这会不加修改地输出匹配的字符参数。要格式化字符串,可以使用%s。
1.5 格式化数字
为了以十进制格式格式化整数,可以使用%d。为了以十进制格式格式化浮点数,可以使用%f。为了以科学计数法格式化浮点数,可以使用%e。使用科学计数法表示的数字,一般形式如下所示:
x.dddddde+/-yy
%g格式说明符会导致Formatter基于被格式化的值和精度使用%f或%e,默认精度值是6。下面的程序演示了%f和%e格式说明符的效果:
//Demonstrate the %f and %e format specifiers.
import java.util.Formatter;
class FormatDemo2 {
public static void main(String[] args) {
Formatter fmt = new Formatter();
for (double i=1.23;i<1.0e+6;i*=100){
fmt.format("%f %e",i, i);
System.out.println(fmt);
}
fmt.close();
}
/**
* 输出:
* 1.230000 1.230000e+00
* 1.230000 1.230000e+00 123.000000 1.230000e+02
* 1.230000 1.230000e+00 123.000000 1.230000e+0212300.000000 1.23
*/
}
通过使用%o和%x,可以使用八进制或十六进制显示整数。例如,下面这行代码:
fmt.format("Hex: %x,Octal: %o",196,196)
产生的输出:
Hex: c4,Octal: 304
通过使用%a,可以使用十六进制格式显示浮点值。咋一看,通过%a生成的格式看起来有些奇怪。这是因为%a使用的表示方式与科学计数法类似,包含一个十六进制底数和一个十进制指数(为2的幂)。一般形式如下所示:
Ox1.sigperp
其中,sig包含底数的小数部分,exp包含指数,p只是后面是指数。例如下面这个调用:
fmt.format("%a",512.0);
生成的输出如下所示:
0x1.0p9
1.6 格式化时间和日期
功能更强大的转换说明符是%t。通过它可以格式化日期和时间信息。%t说明符与其他说明符的工作方式有些不同,因为需要使用后缀来描述时间和日期所期望的组成部分和精确格式。表3显示了这些后缀。例如,为了显示分钟,需要使用%tM。在此,M指示以两个字符宽度的字段显示分钟。与%t对象的参数必须是Calendar、Date、Long或long类型。
后 缀 | 替 换 内 容 |
---|---|
a | 星期名简称 |
A | 星期名全称 |
b | 月份简称 |
B | 月份全称 |
c | 标准日期和时间字符串,格式为:天 月份 日期 小时:分钟:秒钟 时区 年 |
C | 年份的前两个数字 |
d | 每月日期的十进制格式(01-31) |
D | 月/日/年 |
e | 每月日期的十进制格式(1-31) |
F | 年-月-日 |
h | 月份简称 |
H | 小时(00-23) |
I(i的大写) | 小时(01-12) |
j | 每年日期的十进制格式(001-366) |
k | 小时(0-23) |
l (L的小写) | 小时(1-12) |
L | 毫秒(000-999) |
m | 月份的十进制格式(01-13) |
M | 分钟的十进制格式(00-59) |
N | 纳秒(000000000-999999999) |
P | 以小写形式表示本地时间的AM或PM |
Q | 自1970年1月1日以来经历的毫秒数 |
r | 小时:分钟:秒数(12小时格式) |
R | 小时:分钟:秒数(24小时格式) |
S | 秒(00-60) |
s | 自1970年1月1日(UTC)以来经历的毫秒数 |
T | 小时:分钟:秒钟(24小时格式) |
y | 以十进制表示年份(00-99),不含世纪部分(即年份的前两位) |
Y | 以十进制表示的年份(0001-9999),包含世纪部分 |
z | 相对于UTC的时差 |
Z | 时区名 |
下面的程序演示了各种格式:
//Formatting time and date
import java.util.Calendar;
import java.util.Formatter;
class TimeDateFormat {
public static void main(String[] args) {
Formatter fmt = new Formatter();
Calendar cal = Calendar.getInstance();
//Display standard 12-hour time format.
fmt.format("%tr",cal);
System.out.println(fmt);
fmt.close();
//Display complete time and date information.
fmt = new Formatter();
fmt.format("%tc",cal);
System.out.println(fmt);
fmt.close();
//Display just hour and minute.
fmt = new Formatter();
fmt.format("%tl:%tM",cal,cal);
System.out.println(fmt);
fmt.close();
//Display month by name and number.
fmt = new Formatter();
fmt.format("%tB %tb %tm",cal,cal,cal);
System.out.println(fmt);
fmt.close();
/**
* 输出:
* 03:39:42 下午
* 星期日 二月 09 15:39:42 CST 2020
* 3:39
* 二月 二月 02
*/
}
}
1.7 %n和%%说明符
%n和%%格式说明符与其他说明符不同,它们不与参数进行匹配。相反,它们只是插入到输出序列中的转义序列。%n插入一个换行符,%%插入一个百分号。这两个字符否不能直接输入到格式化字符串中,当然,也可以使用标准的转义序列\n嵌入一个换行符。
下面是演示%n和%%格式说明符的例子:
//Demonstrate the %n and %% format specifiers.
import java.util.Formatter;
class FormatDemo3 {
public static void main(String[] args) {
Formatter fmt = new Formatter();
fmt.format("Copying file%nTransfer is %d%% complete",88);
System.out.println(fmt);
fmt.close();
/**
* 输出:
* Copying file
* Transfer is 88% complete
*/
}
}
1.8 指定最小字段宽度
%符号和格式转换代码之前的整数被作为最小字段宽度说明符,这会使用空格填充输出,以确保输出达到特定的最小长度。即便字符串或数字长于最小宽度,也仍然会完整地输出。默认使用空格进行填充。如果希望使用0进行填充,可以在字段宽度说明符之前放置一个0。例如,%05d会使用0填充总长度小于5的数字,从而使数字的总长度为5.字段宽度说明符可以用于除了%n以外的所有格式说明符。
下面的程序演示了应用于%f转换的最小字段宽度说明符:
//Demonstrate a field-width specifier.
import java.util.Formatter;
class FormatDemo4 {
public static void main(String[] args) {
Formatter fmt = new Formatter();
fmt.format("|%f|%n|%12f|%n|%012f|",10.12345,10.12345,10.12345);
System.out.println(fmt);
fmt.close();
/**
* 输出:
* |10.123450|
* | 10.123450|
* |00010.123450|
*/
}
}
第1行默认宽度显示数字10.12345。第2行以12个字符宽度显示数字。第3行以12字符宽度显示数字,不过使用前导0进行填充。
最小字段宽度修饰符经常用于产生对其的表格。例如,下面的程序生成一个表格,用来显示1到10之间数字的平方和立方:
//Create a table of squares and cubes.
import java.util.Formatter;
class FieldWidthDemo {
public static void main(String[] args) {
Formatter fmt;
for(int i=1;i<=10;i++){
fmt=new Formatter();
fmt.format("%4d %4d %4d",i,i*i,i*i*i);
System.out.println(fmt);
fmt.close();
}
/**
* 输出:
* 1 1 1
* 2 4 8
* 3 9 27
* 4 16 64
* 5 25 125
* 6 36 216
* 7 49 343
* 8 64 512
* 9 81 729
* 10 100 1000
*/
}
}