文章目录
- 1. 前言
- 2. 先说结论
- 3. 在结论上补充其他更加特殊情况
- 1. 数字类型可以使用#字符来确认精度
- 2. 数组类型转化需要注意
- 3. 输出特殊字符
- 4. 如何判断一个String是否有替换位
- 4. 粗略原理
1. 前言
-
在工作中发现接口的返回报文,大部分公司通常都会封装一层,具体如下:
// dto封装 { "code": "错误码", "message": "错误信息", "data":"返回数据" } // 报错情况 { "code": "DEMO00001", "message": "插入数据库失败,失败原因:{0}" } // 成功情况 { "code": "success", "data": "返回数据" }
这种返回的好处是在于排查定位问题,可快速找到对应的代码,因为错误码全局只能用一次,不可重复使用,当报错的时候,可以根据这个唯一的错误码找到对应位置。
-
本篇文章当然不是说上述返回的dto,而是对报错情况返回的message特别感兴趣,比较好奇是如何文本替换,进行格式化处理的,查阅资料发现,jdk自带有MessageFormat消息格式化功能,接下来就让我们一起探讨。
2. 先说结论
-
一般使用:
String str = "str:test-format:{0}-{1}"; // 推荐此方法,直接使用静态方法 // 结果:str:test-format:Hello-world System.out.println(MessageFormat.format(str, "Hello", "world")); String str2 = "str2:test-format:{0}-{1}"; // 也可new对象,但不如上面第一种方便 MessageFormat messageFormat = new MessageFormat(str2); // 结果:str2:test-format:Hello-world System.out.println(messageFormat.format(str2, "Hello", "world"));
-
特殊使用:
-
MessageFormat可对时间、日期、数字进行更加特殊格式转化
-
一般使用MessageFormat只会简单的{0},如 str = “test:{0}”,但其实MessageFormat支持的不仅仅是{0},{0}只是其中一个模板写法,其全称模板如下: { ArgumentIndex , FormatType , FormatStyle }
-
ArgumentIndex:数字0,1,2
-
FormatType:格式化类型,支持:
"", // 默认格式 "number", // 数字 "date", // 日期 "time", // 时间 "choice" // 没研究,不考虑 // 例子 String str = "test:{0,number}" String str2 = "test:{0,date}"
-
FormatStyle:格式化风格,支持
// 数字支持 "currency", // 通货格式,通俗就是钱 "percent", // 百分数 "integer" // 整型 // 日期支持 "short", // yy-MM-dd "medium", //yyyy-MM-dd "long", // yyyy年 M月dd日 "full" // yyyy年 M月dd日 星期几 // 时间支持 "short", // 下午h:mm "medium", //hh:mm:ss "long", // 下午hh时mm分ss秒 "full" // 下午hh时mm分ss秒 CST
-
例子
// 数字 String str = "test:{0,number,currency}"; // 结果:test:¥1.20 System.out.println(MessageFormat.format(str,1.2)); String str2 = "test:{0,number,percent}"; // 结果:test:120% System.out.println(MessageFormat.format(str2,1.2)); String str3 = "test:{0,number,integer}"; // 结果:test:1 System.out.println(MessageFormat.format(str3,1.2)); // 日期 String str4 = "test:{0,date,short}"; // 结果:22-12-17 System.out.println(MessageFormat.format(str4, new Date())); String str5 = "test:{0,date,medium}"; // 结果:2022-12-17 System.out.println(MessageFormat.format(str5, new Date())); String str6 = "test:{0,date,long}"; // 结果:2022年12月17日 System.out.println(MessageFormat.format(str6, new Date())); String str7 = "test:{0,date,full}"; // 结果:2022年12月17日 星期六 System.out.println(MessageFormat.format(str7, new Date())); // 时间 String str4 = "test:{0,time,short}"; // 结果:下午2:41 System.out.println(MessageFormat.format(str4, new Date())); String str5 = "test:{0,time,medium}"; // 结果:14:41:52 System.out.println(MessageFormat.format(str5, new Date())); String str6 = "test:{0,time,long}"; // 结果:下午02时41分52秒 System.out.println(MessageFormat.format(str6, new Date())); String str7 = "test:{0,time,full}"; // 结果:下午02时41分52秒 CST System.out.println(MessageFormat.format(str7, new Date()));
-
3. 在结论上补充其他更加特殊情况
1. 数字类型可以使用#字符来确认精度
String str = "test:{0,number,#.##}";
// 结果:test:1.23
System.out.println(MessageFormat.format(str, 1.23456));
String str2 = "test:{0,number,#.##}";
// 结果:test:1.2
// 不会自动补零
System.out.println(MessageFormat.format(str2, 1.2));
2. 数组类型转化需要注意
// 第一种情况
Object[] typeParams = {"A", "B", "C"};
// 只有一个要替换格式
String str2 = "str2:test-format:{0}";
// 结果:str2:test-format:A
// 因为MessageFormat.format的第二个参数本身就是可变参数
// 又刚刚好,传递了一个数组,默认会认为数组里面的内容,是替换参数的数量以及值
// 不会觉得你传递的typeParams是一个整体要输出
System.out.println(MessageFormat.format(str2, typeParams));
// 第二种情况
Object[] typeParams = {"A", "B", "C"};
String str2 = "str2:test-format:{0}-{1}";
// 结果:str2:test-format:类型有-[Ljava.lang.Object;@1218025c
System.out.println(MessageFormat.format(str2, "类型有", typeParams));
// 结果:str2:test-format:类型有-[A, B, C]
System.out.println(MessageFormat.format(str2, "类型有", Arrays.toString(typeParams)));
3. 输出特殊字符
// 输出双引号,使用 \ 转义符
String str2 = "str2:test-format:\"a\"-\"{0}\"-\"c\"";
// 结果:str2:test-format:"a"-"b"-"c"
System.out.println(MessageFormat.format(str2, "b"));
// 输出{}号,使用 ' 单引号
String str2 = "str2:test-format:'{'a'}'-'{'{0}'}'-'{'c'}'";
// 结果:str2:test-format:{a}-{b}-{c}
System.out.println(MessageFormat.format(str2, "b"));
// 输出单引号,使用 '' 两个单引号代表输出一个单引号
String str2 = "str2:test-format:''a''-''{0}''-''c''";
// 结果:str2:test-format:'a'-'b'-'c'
System.out.println(MessageFormat.format(str2, "b"));
4. 如何判断一个String是否有替换位
MessageFormat.getFormats方法是将得到一个数组,数组个数即是字符串中{0}{1}有几个替换位
String str1 = "{0}-{1}-{2}-{3}";
MessageFormat messageFormat = new MessageFormat(str1);
// 结果:4
System.out.println(messageFormat.getFormats().length);
String str2 = "test";
MessageFormat messageFormat2 = new MessageFormat(str2);
// 结果:0
System.out.println(messageFormat2.getFormats().length);
4. 粗略原理
- MessageFormat的底层源码太多了,这里就粗略简述其的现实方式,不细扣细节了,其实现原理:就是对输入的字符串一个个扫描,匹配是否有{ } 括号,做相关处理。
为什么需要知道去掉替换符的字符串呢?
其实是配合offsets偏移量使用的,比如第一个替换符位置是第五位,传入参数是A,那么:pattern.substring(0, 5) + A
就达到了:实际上就是字符串拼接,但效果就是替换