JDK9之后对String底层存储数据结构进行了重大的修改1,同步也增加了许多新的方法,主要有Text Blocks、chars()、codePoints()、describeConstable()、formatted()、indent()、isBlank()、isEmpty()、lines()、repeat()、strip()、stripLeading()、stripIndent()、stripTrailing()、translateEscapes(),接下来就逐一看看每个方法怎么用。

Text Blocks

在JDK8之前我们想定义一个JSON String必须要各种转义、拼接,可读性非常差,看起来也比较乱,JDK17里我们可以使用"""来定义一个text block,看起来清爽多了

//JDK8之前想要定义一个JSON数据格式
        String json = "{\n" +
                "    \"name\": \"admin\",\n" +
                "    \"id\": 1\n" +
                "}";
        String json2 = """
                {
                    "name": "admin",
                    "id": 1
                }""";
        //JDK17+
        System.out.println(json);
        System.out.println(json2);
        //true
        System.out.println(json.equals(json2));

使用Text Blocks需要注意以下几点:

  1. Text Blocks就是个语法糖,编译后还是和之前一样
  2. 前后"““必须放在两行,不能放同一行代码中,第一行的””"后面不能放字符串,不然会报Illegal text block start: missing new line after opening quotes

chars()

String name = "12345工😃";
        //JDK9+ 获取String中所有char字符,一个emoji会获取到多个char
        IntStream chars = name.chars();
        chars.forEach(x -> System.out.println(Character.toChars(x)));
        //输出
        1
        2
        3
        4
        5
        工
        ?
        ?

codePoints()

String name = "12345工😃";  
        //JDK9+ 获取String中所有char emoji会拆一个  
        IntStream chars = name.codePoints();  
        chars.forEach(x -> System.out.println(Character.toChars(x)));  
        //输出  
        1  
        2  
        3  
        4  
        5  
        工  
        😃

chars()和codePoints()都是获取String中的char,主要区别是codePoints()获取char支持的编码更多了,如果是emoji chars()会得到两个char,codePoints()只会获取一个,想要了解具体的char编码可以参考《其实你并不懂 Unicode》2;

describeConstable()、resolveConstantDesc()

String name = "12345工😃";
        //JDK12+
        Optional<String> optionalString = name.describeConstable();
        System.out.println(optionalString.get());
        
        public Optional<String> describeConstable() {
             return Optional.of(this);
         }

这个方法比较简单,就是返回一个Optional对象,加入这个方法的主要原因是String实现了Constable和ConstantDesc两个接口,实现这两个接口的目的是JAVA
引入了新的API以对关键类文件和运行时工件的名义描述进行建模,尤其是可以从常量池中加载的常量3

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence,
               Constable, ConstantDesc {
        }
        
    public interface Constable {
        Optional<? extends ConstantDesc> describeConstable();
    }
    
    public sealed interface ConstantDesc
        permits ClassDesc,
                MethodHandleDesc,
                MethodTypeDesc,
                Double,
                DynamicConstantDesc,
                Float,
                Integer,
                Long,
                String {
            Object resolveConstantDesc(MethodHandles.Lookup lookup) throws ReflectiveOperationException;
    }

formatted()

String name = "12345工😃%s-%d";
        //JDK15+
        String formattedString = name.formatted("admin",1);
        Assertions.assertEquals(String.format(name,"admin",1),formattedString);

formatted()方法等同步于String.format()

indent()

String name = "1\n2\n3\r4";
        //JDK11 按行缩进
        String indentString = name.indent(20);
        System.out.println("|" + indentString + "|");
        //输出 
        |            1
                    2
                    3
                    4
        |

indent()可以缩进字符串,并且可以按\n、\r、\r\n拆分后将每一行都缩进指定空格

isBlank()、isEmpty()

//true
        System.out.println("".isBlank());
        //true
        System.out.println("".isEmpty());
        //true        
        System.out.println(" ".isBlank());
        //false
        System.out.println(" ".isEmpty());
        //true
        System.out.println("\t\n".isBlank());
        //false
        System.out.println("\n\n".isEmpty());

这两个方法可以方便我们判断字符串是否为空了

lines()

String name = "1\n2\r3\r\n4";
        //JDK11+ 按\n\r拆分String
        List<String> lines = name.lines().collect(Collectors.toList());
        lines.forEach(System.out::println);
      //输出
        1
        2
        3
        4

lines()方法可以快速的帮我们将String 按\n、\r、\r\n拆分成一行一行

repeat()

String name = "Admin";
        //JDK11+ 重复String
        String jdkRepeatString = name.repeat(3);
        /AdminAdminAdmin
        System.out.println(jdkRepeatString);

repeat()将字符串重复拼接n次

strip()

String name = "\u0020 \t admin\0";
        //JDK11+
        System.out.println(name.strip() + "|");
        System.out.println(name.trim() + "|");
        //输出
        admin |
        admin|

strip()和trim()有点类似,不同的是trim()仅删除字符 <= U+0020(空格);strip()删除所有 Unicode 空白字符(但不是所有控制字符,例如 \0)

stripLeading()、stripIndent()、stripTrailing()

String name = " admin \n admin ";
        //JDK11+
        System.out.println("|"+name.stripLeading()+"|");
        System.out.println("-------------");
        System.out.println("|"+name.stripIndent()+"|");
        System.out.println("-------------");
        System.out.println("|"+name.stripTrailing()+"|");
        //输出
        |admin 
         admin |
        -------------
        |admin
        admin|
        -------------
        | admin 
         admin|

stripLeading()去除前面的空格,stripIndent()可以按\n、\r、\r\n拆分后按行去除前后空格,stripTrailing()去除后面空格

translateEscapes()

String name = "\b\r\t\f";
        //JDK15+
        String transform = name.translateEscapes();
        System.out.println(transform);

将\b\t\n\f等字面字符转义

JDK17新特性之--JDK9到JDK17 String 新增的新方法_字符串


  1. JDK17新特性之–新的Compact Strings(JEP 254)
  2. 其实你并不懂 Unicode - 知乎 ↩︎
  3. JEP 334: JVM Constants API ↩︎