在高版本的 Java 中,字符串操作新增了如下方法:
| Java 版本 | 方法名 | 方法描述 | 
| 9 | chars() | 返回字符串的字符值流 | 
| 9 | codePoints() | 返回字符串的 Unicode 值流 | 
| 11 | strip() | 移除首尾空白字符(支持所有 Unicode 字符) | 
| 11 | stripLeading() | 移除头部空白字符 | 
| 11 | stripTrailing() | 移除尾部空白字符 | 
| 11 | isBlank() | 检查字符串是否只包含空白字符 | 
| 11 | repeat(int count) | 返回一个由原始字符串重复 count次组成的新字符串 | 
| 11 | lines() | 使用换行符将字符串拆分为一个流 | 
| 12 | indent(int n) | 根据参数 n的值调整字符串的缩进 | 
| 12 | transform(Function<? super String, ? extends R> f) | 使用给定的函数 f对字符串进行转换 | 
| 12 | describeConstable | 创建并返回一个实例本身的 Optional对象 | 
| 15 | formatted(Object... args) | 使用提供的参数替换占位符,并返回一个格式化的字符串 | 
| 15 | stripIndent() | 移除首尾空白字符(包含换行符前后的) | 
| 15 | translateEscapes() | 将字符串中的转义序列转换为对应的字符 | 
在 Java 9 中的 String 类新增了 chars 和 codePoints 方法,用于获取字符的 IntStream:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
 | // 测试内容
String testContent = "中-E-\uD835\uDD0A";
// 测试 chars
System.out.println();
System.out.println("chars:");
IntStream intStreamChars = testContent.chars();
intStreamChars.forEach(e -> System.out.print(e + "=" + (char) e + "  "));
// 测试 codePoints
System.out.println();
System.out.println("codePoints:");
IntStream intStreamCodePoints = testContent.codePoints();
intStreamCodePoints.forEach(e -> System.out.print(e + "=" + (char) e + "  "));
 | 
 
两者都是获取字符串中的字符 ASCII 码的 IntStream 流,但 codePoints 方法可以处理 Unicode 特殊字符,输出结果如下:

|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
 | // 测试内容
String testContent = "\u2000中-E-\uD835\uDD0A-\u2000  ";
// 移除首尾空白字符(仅限 ASCII 字符)
System.out.println("text.trim():" + testContent.trim());
// Java 11 新增 - 移除首尾空白字符(支持所有 Unicode 字符)
System.out.println("text.strip():" + testContent.strip());
// Java 11 新增 - 移除头部空白字符
System.out.println("text.stripLeading():" + testContent.stripLeading());
// Java 11 新增 - 移除尾部空白字符
System.out.println("text.stripTrailing():" + testContent.stripTrailing());
// Java 15 新增 - 移除首尾空白字符(包含换行符前后的)
testContent = " \u2000中-E-回车: \n :回车 \u2000  ";
System.out.println("text.stripIndent():" + testContent.stripIndent());
 | 
 
输出结果:

仔细看这里的 trim 和 strip 方法:
trim 方法仅限 ASCII 编码的空白字符,strip 可以移除所有 Unicode 编码的空白字符。
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
 | // 测试内容
String testContent = " ";
// Java 6 新增 - 判断是否为空白字符
// 输出:false
System.out.println(testContent.isEmpty());
// Java 11 新增 - 判断是否为空白字符
// 输出:true
System.out.println(testContent.isBlank());
// 空指针异常处理
// 输出:Cannot invoke "String.isBlank()" because "testContent2" is null
String testContent2 = null;
System.out.println(testContent2.isBlank());
 | 
 
isEmpty 和 isBlank 方法最大的区别就是对空白字符串的判断,如果字符串仅仅包含空白字符,isEmpty 为真,isBlank 为假。
如果字符串为 null,使用这两个方法都会抛出空指针异常。
在 Java 11 中新添加重复拼接字符串 repeat 方法,比如下面示例:
| 1
2
 | String testContent = "hello~ ";
System.out.println(testContent.repeat(3));
 | 
 
输出结果:

其底层调用了 System.arraycopy 方法进行字节拷贝,最后再封装成一个新的字符串。
Java 11 新增方法。根据字符串的换行符,将每个字符形成一个 Stream 流:
| 1
2
3
4
5
6
 | // 测试内容
String testContent = "hello\njava\nC++\nPHP\nGO\n";
// 返回 Stream 流的数量
System.out.println("数量:" + testContent.lines().count());
// 遍历 Stream 流输出
testContent.lines().forEach(System.out::println);
 | 
 
输出结果:

indent 是 Java 12 新增方法,用于对字符串进行缩进:
| 1
2
 | String testContent = "hello\njava\nC++\nPHP\nGO\n";
System.out.println(testContent.indent(3));
 | 
 
输出结果:

来看它的源码:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 | /**
 * 缩进字符串
 * @param n 缩进的空格数
 * @return 缩进后的字符串
 */
public String indent(int n) {
    // 如果字符串为空,则直接返回空字符串
    if (isEmpty()) {
        return "";
    }
    // 获取每一行字符串
    Stream<String> stream = lines();
    // 如果缩进数大于 0
    if (n > 0) {
        // 生成包含 n 个空格的字符串
        final String spaces = " ".repeat(n);
        // 对每一行字符串进行处理,将其前面添加 n 个空格
        stream = stream.map(s -> spaces + s);
    } else if (n == Integer.MIN_VALUE) {
        // 对每一行字符串进行处理,去除开头的空格
        stream = stream.map(s -> s.stripLeading());
    } else if (n < 0) {
        // 对每一行字符串进行处理,截取从开头到第一个非空格字符之间的子字符串
        stream = stream.map(s -> s.substring(Math.min(-n, s.indexOfNonWhitespace())));
    }
    // 将每一行字符串通过换行符连接起来,并返回结果
    return stream.collect(Collectors.joining("\n", "", "\n"));
}
 | 
 
其实就是调用了上面的 lines 方法根据根据换行符来创建一个 Stream,然后再往前拼接指定数量的空格,最后形成新的字符串。
transform 是 Java 12 新增的方法,用于字符串转换:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
 | // 测试内容
String testContent = " 自本非美玉,故不敢加以刻苦雕琢 ";
/*
 * 对测试内容进行处理:
 * 1. 移除首尾空白字符(strip 方法)
 * 2. 转换为大写(toUpperCase 方法)
 * 3. 将处理后的字符串拼接为 "我深怕" 开头的新字符串
 */
String result = testContent.transform(String::strip)
        .transform(String::toUpperCase)
        .transform(e -> "我深怕" + e);
System.out.println(result);
 | 
 
这里先用 strip 移除前后的空白字符,然后转换为大写,最后再拼接一个前缀。
结果输出:

Java 12 中的 String 实现了 Constable 接口:
| 1
2
3
4
5
6
7
8
9
 | public interface Constable {
    /*
     * 如果可以构建该实例的名义描述符,则返回一个包含它的 {@link Optional} 对象
     * 若无法构建,则返回一个空的 {@link Optional} 对象。
     *
     * @return 包含生成的名义描述符的 {@link Optional} 对象,如果无法构建则返回一个空的 {@link Optional} 对象。
     */
    Optional<? extends ConstantDesc> describeConstable();
}
 | 
 
实现源码如下所示:
| 1
2
3
4
5
6
7
8
9
 | /*
 * 返回一个包含当前对象的 {@link Optional} 对象。
 *
 * @return 包含当前对象的 {@link Optional} 对象。
 */
@Override
public Optional<String> describeConstable() {
    return Optional.of(this);
}
 | 
 
其实就是把字符串本身封装一个 Optional 对象返回。
示例代码如下:
|  1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
 | // 测试内容
String testContent = "却又半信自己是块美玉,故又不肯庸庸碌碌,与瓦砾为伍";
Optional<String> nameOptional = testContent.describeConstable();
// 直接 get 会提示如下信息:
// 'Optional.get()' without 'isPresent()' check
System.out.println(nameOptional.get());
// 此处相当于:
// 1. 使用 'isPresent()' 方法检查 Optional 是否包含值
// 2. 打印 Optional 中的值
// if (nameOptional.isPresent()) {
//     System.out.println(nameOptional.get());
// }
nameOptional.ifPresent(System.out::println);
 | 
 
输出结果:
却又半信自己是块美玉,故又不肯庸庸碌碌,与瓦砾为伍
Optional 是 Java 8 中的新特性,可用来替代对象的 != null 判断。
Java 15 中的 String 类引入了一个 formatted() 格式化新方法,它是 String.format() 方法的简写版本,它可以方便地对字符串进行格式化。
| 1
2
3
4
5
6
 | String testContent1 = "Hello, %s".formatted("Linux do!");
System.out.println(testContent1);
// 白白白是一只雪白的猫猫
String testContent2 = "我叫 %s,我今年已经 %d 岁啦~".formatted("白白白", 3);
System.out.println(testContent2);
 | 
 
输出结果:

在 Java 15 中,String 类引入了 translateEscapes() 新方法,用于将字符串中的转义序列转化为相应的字符。
来看下面的示例代码:
| 1
2
3
4
5
6
7
8
 | String testContent = "Hello\n\\n白白白\\t!";
System.out.println("===testContent===");
System.out.println(testContent);
System.out.println();
System.out.println("===translateEscapes===");
System.out.println(testContent.translateEscapes());
 | 
 
输出结果:

通过前面输出对比可以看出,正常的转义字符 \\n 经过转换一次之后变成了 \n 就不能再转换了,而新出的 translateEscapes 方法可以继续转换出转义之后的转义字符,把所有转义字符转换为真正的字符。
支持的转义字符如下:
| 转义序列 | 对应的字符 | 
| \b | 退格符 (Backspace) | 
| \t | 制表符 (Tab) | 
| \n | 换行符 (Newline) | 
| \f | 换页符 (Form feed) | 
| \r | 回车符 (Carriage return) | 
| \" | 双引号 (Double quote) | 
| \' | 单引号 (Single quote) | 
| \\ | 反斜线 (Backslash) | 
| \0to\377 | 八进制表示的 Unicode 字符 | 
| \s | 空格符 (Space) |