不论是哪个编程语言, 拼接字符串都是一个频繁的操作, 很多的语言都支持通过重载"+"号运算符来拼接字符串, 这也是最常见快捷及直观的方式.
除了用"+"号拼接外, 有的语言还支持更先进的拼接方式, 比比较新版本的 javascript 语言还支持比较优雅的利用 ${XXX} 的方式去传递变量值, 这就已经基本接近了很多模板技术的写法了, 比如这样:
let name = '小明';
let age = 20;
console.log(`他的名字叫${name}, 他今年${age}岁.`); // 注意字符串用键盘左上角的撇号(`)括起来而不是引号
对于这样一个比较长又涉及好几个变量, 变量通常还是夹在字符串中间的情况, 如果使用传统的 + 号方式去拼接, 虽然不是不可以, 但往往显得支离破碎的, 写起来麻烦, 一堆的加号及引号, 看上去对整句的把握上也不友好直观:
let name = '小明';
let age = 20;
console.log('他的名字叫' + name + ', 他今年' + age + '岁.');
应该说, + 号式的拼接对于比较简短的, 只有一个变量接在最后的情况还是比较方便的, 但类似上述的情况, 往往就有点力不从心了, 而此时像 javascript 这种利用 ${XXX} 占位符的方式就友好很多了.
当然, 这是 javascript 的情况, Java 语言呢? 有点遗憾, Java 对于 ${XXX} 这种直接取变量名的方式仍然是不支持的, 不过它还是有自己的占位符方式, 还是可以避免把字符串弄得支离破碎的, 这个方式便是利用 String.format 方法结合 %x 占位符的方式, 比如上述例子可以这样:
package net.xiaogd.core.java.basic;
import org.junit.Assert;
import org.junit.Test;
public class StringFormatTest {
@Test
public void stringFormat() {
String name = "小明";
int age = 20;
String str = String.format("他的名字叫%s, 他今年%d岁.", name, age);
Assert.assertEquals("他的名字叫小明, 他今年20岁.", str);
}
}
通过 %x 占位符的方式, 同样避免了使用 + 号时把字符串弄得支离破碎的情况, 直接在一个双引号里面就写完了.
在这里, 第一个变量 name, 也即是 String.format 的第二个参数, 会传递给字符串中的第一个占位符 %s:
%s 中 s 代表 string, 也即是字符串类型.
而第二个变量, 也即是 String.format 的第三个参数, 会传递给字符串中的第二个占位符 %d:
%d 中 d 代表 decimal integer, 也即是十进制整型.
如果字符串中有更多的占位符, 就相应传入更多的变量即可.
String.format 方法是一个可接收可变长参数的方法.
%X 的这种写法, 除了作为占位符之外, 还支持一定的格式化操作, 比如下述代码中, 用 %03d 的方式把不足三位的数字用前补零的方式补足三位去显示:
package net.xiaogd.core.java.basic;
import org.junit.Assert;
import org.junit.Test;
public class StringFormatTest {
@Test
public void stringFormatAlign() {
// 把不足三位的数字用前补零的方式补足三位去显示
String str = String.format("随机抽中的三个号码是 %03d, %03d, %03d.", 1, 135, 23);
Assert.assertEquals("随机抽中的三个号码是 001, 135, 023.", str);
}
}
在上述代码中, %d 前面说了, 是输出十进制整型用的, 而 %03d 中, 3 表示显示为 3 位的宽度, 0 则表示不足三位宽度的用前置零补足.
而如果不打算用零去填充, 而只是指定一个宽度, 则会用空格填充, 如下所示:
package net.xiaogd.core.java.basic;
import org.junit.Assert;
import org.junit.Test;
public class StringFormatTest {
@Test
public void stringFormatAlign2() {
// 把不足四位的数字用前补空格的方式补足四位去显示
// 为便于观察, 使用中括号[]括起内容
String str2 = String.format("随机抽中的四个号码是 [%4d], [%4d], [%4d], [%4d].", 2, 1293, 43, 100);
Assert.assertEquals("随机抽中的四个号码是 [ 2], [1293], [ 43], [ 100].", str2);
}
}
另外, 上述的填充方式是右对齐的, 如果打算左对齐, 则可以使用"-"符号来实现:
package net.xiaogd.core.java.basic;
import org.junit.Assert;
import org.junit.Test;
public class StringFormatTest {
@Test
public void stringFormatAlign3() {
// - 表示左对齐, 也即右补空格
// 为便于观察, 使用中括号[]括起内容
String str3 = String.format("随机抽中的三个号码是 [%-3d], [%-3d], [%-3d].", 1, 135, 23);
Assert.assertEquals("随机抽中的三个号码是 [1 ], [135], [23 ].", str3);
}
}
此外, 还支持变量的复用, 比如下述例子, 两个变量都分别被用了两次, 这时可以使用 %1 s , s, %2 s,s 这样的表示法, 其中, 1 , 2 , 2 ,2 表示依次取得第一个以及第二个参数的值, 如果有更多变量, 则依次类推:
package net.xiaogd.core.java.basic;
import org.junit.Assert;
import org.junit.Test;
public class StringFormatTest {
@Test
public void stringFormatReuse() {
String xm = "小明";
String xh = "小红";
String str = String.format("%1$s喜欢%2$s, %2$s也喜欢%1$s.", xm, xh);
Assert.assertEquals("小明喜欢小红, 小红也喜欢小明.", str);
}
}
而如果不打算这样使用的话, 则需要传递四次变量, 每个依次对应一个 %s 的占位符, 如下述写法, 与前述做法结果一样:
package net.xiaogd.core.java.basic;
import org.junit.Assert;
import org.junit.Test;
public class StringFormatTest {
@Test
public void stringFormatNotReuse() {
String xm = "小明";
String xh = "小红";
String str = String.format("%s喜欢%s, %s也喜欢%s.", xm, xh, xh, xm);
Assert.assertEquals("小明喜欢小红, 小红也喜欢小明.", str);
}
}
String.format 还支持更多的格式化的操作, 这个具体就要读者自己去看它的文档了.
其实它内部也是使用了
Formatter
这个类去实现的, 所以应该看的是java.util.Formatter
这个类的文档, 里面有更多的用法介绍, 包括格式化小数, 日期, 货币等等的操作.
其实正如 format 这个方法名所暗示的, 它主要是关于格式化字符串的, 但它正好也给出了一种拼接字符串的较为优雅的方式, 所以, 即便你不关心字符串的格式化, 依然可以利用它的这个特性去做字符串常量与变量的拼接, 从而提高代码的可读性.