public Formatter format(Locale l, String format, Object ... args) {
format的方法主体。
参数释义:
Locale l:本地化参数 在格式化的过程中的应用环境配置信息,如果该参数的值为空,那么不会进行本地化,如果不为空,那么将会按照该参数的环境配置信息进行本地化。
String format:格式化字符串 按照个性定义的规则形成的格式化字符串。
Object ... args:不定参数 略。
ensureOpen();
确保开放。
对参数a进行判断,如果参数a为空,那么将抛出FormatterClosedException异常(格式化程序异常关闭)。
private void ensureOpen() {
if (a == null)
throw new FormatterClosedException();
}
其中参数a为----
private Appendable a;
对Appendable接口进行分析:
Appendable接口的实现类的对象(即为参数a)能够被添加 char 序列和值。接受Format的格式化输出。
int last = -1;
表示最后一个参数的索引值。
int lasto = -1;
表示最后一个普通索引值。
FormatString[] fsa = parse(format);
定义类型为FormatString[] 的数组,命名为fsa,并赋值为将参数format(格式化字符串)方法parse()的返回值。
方法parse解析:
方法功能:在格式化字符串(format)中找到格式说明符(例如%s)。
private FormatString[] parse(String s) {
将传入到方法中的格式化字符串(format)命名为字符串s。
ArrayList<FormatString> al = new ArrayList<>();
创建一个FortmatString接口方法的数组列表命名为a1。
FormatString接口方法解析:
private interface FormatString {
在该接口方法中声明了三个方法。
分别是:
FormatString.index();
FormatString.print(Object arg,Locale l);
FormatString.toString();
int index();
void print(Object arg, Locale l) throws IOException;
String toString();
由于这里只是方法的声明接口,还未做出具体的实现功能,因此在这里我们不会对这三个方法的实现做出解析,在使用方法时在进行相应的方法详细解析。
}
Matcher m = fsPattern.matcher(s);
定义一个Matcher,其功能类似于是为了创建一个正则表达式操作台(就是这里的fsPattern)的相对应的操作员Matcher m,并且将格式化字符串(参数s)作为本次正则操作的操作对象。Matcher中的具体方法在这里不做具体说明。
关于正则表达式:
以下为匹配的正则表达式:
%[argument_index$][flags][width][.precision][t]conversion
private static final String formatSpecifier
= "%(\d+\$)?([-#+ 0,(\<]*)?(\d+)?(\.\d+)?([tT])?([a-zA-Z%])";
private static Pattern fsPattern = Pattern.compile(formatSpecifier);
for (int i = 0, len = s.length(); i < len; ) {
对传入方法的格式化字符串(参数s)进行遍历处理。
if (m.find(i)) {
从格式化字符串的第i项开始匹配如果可以匹配到,那么返回true。
字符串开头和格式说明符之间的任何内容都是固定文本或包含无效格式字符串。
if (m.start() != i) {
如果能匹配到的位置不是当前位置。那么检查文本。确保我们没有错过任何一个无效的格式说明符。
checkText(s, i, m.start());
检查文本checkText方法解析。
private static void checkText(String s, int start, int end) {
方法的大致意思是用来检查文本。
参数释义:
String s:格式化字符串 要处理的格式化字符串。
int start:检查开始位置 就是遍历的当前位置。
int end:检查结束位置 可以匹配到正则表达式的开始位置。
for (int i = start; i < end; i++) {
在该区域中发现的任何一个“%”启动无效的格式说明符。
if (s.charAt(i) == '%') {
如果发现了在这段字符串内有%。
char c = (i == end - 1) ? '%' : s.charAt(i + 1);
i的值是否等于end - 1,如果是,那么将’%’赋值给字符c,如果不是,那么将格式化字符串当前位置的字符的后一项字符赋值给字符c。
throw new UnknownFormatConversionException(String.valueOf(c));
并且抛出异常UnknownFormatConversionException(未知格式转换异常)。并将字符串c传入到该异常方法中。
UnknownFormatConversionException方法解析:
用未知的转换构造该类的实例。
public UnknownFormatConversionException(String s) {
if (s == null)
throw new NullPointerException();
this.s = s;
}
}
}
}
al.add(new FixedString(s.substring(i, m.start())));
将从当前位置i到匹配到正则表达式m.start()中间的字符串实例化FixedString并且给添加给表单。
FixedString接口
private class FixedString implements FormatString {
private String s;
FixedString(String s) { this.s = s; }
public int index() { return -2; }
public void print(Object arg, Locale l)
throws IOException { a.append(s); }
public String toString() { return s; }
}
}
如果当前位置就是能匹配到正则表达式的开始,那么将正则表达式的操作员实例化给FormatSpecifier并添加到表单。
al.add(new FormatSpecifier(m));
i = m.end();
将i的值直接赋值到正则匹配结束的位置值,将中间的所匹配的字段直接跳过便利循环中,从匹配结束的位置继续开始便利操作。
} else {
如果当前位置的后面匹配不到符合正则表达式的字符串,那么。
那么说明没有更有效的格式说明符。
checkText(s, i, len);
检查可能的无效格式说明符。
其余的字符串都是固定的文本。
al.add(new FixedString(s.substring(i)));
从当前位置的字符开始截取一直截取到格式化字符串的末尾字符,将此段字符串实例化给FixedString方法中去,并且添加到列表中去。
break;
跳出遍历循环。
}
}
return al.toArray(new FormatString[al.size()]);
将列表变为FormatString类型的数组长度为al.size()。
}
for (int i = 0; i < fsa.length; i++) {
FormatString fs = fsa[i];
int index = fs.index();
try {
switch (index) {
case -2: // fixed string, "%n", or "%%"
fs.print(null, l);
break;
case -1: // relative index
if (last < 0 || (args != null && last > args.length - 1))
throw new MissingFormatArgumentException(fs.toString());
fs.print((args == null ? null : args[last]), l);
break;
case 0: // ordinary index
lasto++;
last = lasto;
if (args != null && lasto > args.length - 1)
throw new MissingFormatArgumentException(fs.toString());
fs.print((args == null ? null : args[lasto]), l);
break;
default: // explicit index
last = index - 1;
if (args != null && last > args.length - 1)
throw new MissingFormatArgumentException(fs.toString());
fs.print((args == null ? null : args[last]), l);
break;
}
} catch (IOException x) {
lastException = x;
}
}
return this;
}