JDK JDK 学习手册8 → 27 · JDK 专用学习站
QUICKREF · CORE API · JDK 11

String 与 Files:JDK 11 的文本便利方法

JDK 11 · 速查主题 03 / 06 · 预计 22 分钟
基础22 分钟
一句话JDK 11 给 String 增加了 isBlank、lines、strip、repeat,给 Files 增加了 readString / writeString。它们都很小,但编码边界比方法本身重要:Files 的默认编码是 UTF-8,而 JDK 11 的 Charset.defaultCharset() 仍然取决于平台。

学完你要能自己回答

  1. isBlank 与 isEmpty、strip 与 trim 的边界分别是什么?
  2. lines() 如何处理 \n、\r\n 和末尾空行?Files.lines 返回的 Stream 需要关闭吗?
  3. Files.readString / writeString 默认用什么编码?为什么不等于 Charset.defaultCharset()?

四个新方法:空白、行、裁剪、重复01

JDK 11 的 String 增加了四个日常方法。它们都不是语法糖,而是把常见的字符串处理从正则和手工循环里拿出来。

方法作用边界
isBlank()是否只包含空白字符使用 Character.isWhitespace;空串返回 true
lines()按 \n、\r、\r\n 切分为 Stream<String>不保留行终止符;末尾终止符不产生空元素
strip() / stripLeading() / stripTrailing()去掉首尾空白使用 Character.isWhitespace,覆盖 Unicode 空白
repeat(int n)重复 n 次n=0 返回空串;n<0 抛 IllegalArgumentException
import java.util.stream.Collectors;

public class StringDemo {
    public static void main(String[] args) {
        String s = "  \u2003Java 11\u2003  ";
        System.out.println("blank=" + " \t\n".isBlank());
        System.out.println("isEmpty=" + " \t\n".isEmpty());
        System.out.println("stripLen=" + s.strip().length());
        System.out.println("trimLen=" + s.trim().length());
        System.out.println("repeat=" + "ab".repeat(3));
        System.out.println("repeat0=[" + "ab".repeat(0) + "]");
        System.out.println("lines=" + "a\nb\r\nc".lines().collect(Collectors.toList()));
        System.out.println("trailing=" + "a\n".lines().collect(Collectors.toList()));
        System.out.println("blankLine=" + "a\n\nb".lines().collect(Collectors.toList()));

        try {
            "ab".repeat(-1);
        } catch (IllegalArgumentException e) {
            System.out.println("repeat(-1)=" + e.getClass().getSimpleName());
        }
    }
}
blank=true
isEmpty=false
stripLen=7
trimLen=9
repeat=ababab
repeat0=[]
lines=[a, b, c]
trailing=[a]
blankLine=[a, , b]
repeat(-1)=IllegalArgumentException

lines() 在遇到末尾换行时不会额外产生一个空串:"a\n".lines() 只有一个元素 a。但两个换行之间确实有空行,"a\n\nb" 会得到 [a, , b]。

strip 与 trim:Unicode 空白的差别02

trim() 的规则是去掉首尾所有码点小于等于 U+0020 的字符;strip() 使用 Character.isWhitespace,能处理更多 Unicode 空白,例如 U+2003 EM SPACE。

String s = "  \u2003Java 11\u2003  ";
System.out.println(s.strip().length()); // 7
System.out.println(s.trim().length());  // 9

System.out.println("\u00A0".isBlank());            // false
System.out.println("\u00A0x\u00A0".strip().length()); // 3
7
9
false
3

U+00A0 NO-BREAK SPACE 是一个例外:它是空格字符,但 Character.isWhitespace 返回 false,所以 isBlank() 不认为它空白,strip() 也不会去掉它。需要处理 NBSP 时要自己替换或使用正则。

输入trimstrip说明
首尾普通空格去掉去掉行为一致
U+2003 EM SPACE保留去掉strip 覆盖 Unicode 空白
U+00A0 NBSP保留保留不是 Character.isWhitespace
制表符 / 换行去掉去掉都属于空白
从 JDK 11 开始写新代码,优先用 strip;只有需要兼容旧行为或明确只处理 ASCII 空格时才用 trim。

Files.readString 与 writeString03

JDK 11 的 Files 增加了整文件读写的快捷方法:readString(Path) 与 writeString(Path, CharSequence, OpenOption...)。它们默认使用 UTF-8,不是平台默认编码。

import java.nio.charset.MalformedInputException;
import java.nio.file.*;

public class FilesDemo {
    public static void main(String[] args) throws Exception {
        Path p = Path.of("demo.txt");
        Files.writeString(p, "line1\nline2\n");
        System.out.println("read=" + Files.readString(p).lines().count());

        Files.writeString(p, "line3\n", StandardOpenOption.APPEND);
        System.out.println("lines=" + Files.readAllLines(p));
        System.out.println("size=" + Files.size(p));

        Path bad = Path.of("bad.txt");
        Files.write(bad, new byte[]{(byte) 0xC3, (byte) 0x28});
        try {
            Files.readString(bad);
        } catch (MalformedInputException e) {
            System.out.println("bad=" + e.getClass().getSimpleName());
        }
    }
}
read=2
lines=[line1, line2, line3]
size=18
bad=MalformedInputException
  • readString 一次性把整个文件读进内存;大文件应使用 Files.lines 或 BufferedReader。
  • writeString 的默认打开选项是 CREATE、TRUNCATE_EXISTING、WRITE;追加要显式传 StandardOpenOption.APPEND。
  • readString 用 UTF-8 严格解码,遇到非法字节抛 MalformedInputException;不会静默替换。
  • Files.lines 返回的 Stream 持有文件句柄,必须用 try-with-resources 关闭;String.lines() 不需要关闭。
  • 需要其他编码时用 readString(path, charset) / writeString(path, text, charset, options)。
try (var lines = Files.lines(path)) {
    lines.forEach(System.out::println);
}
Files.readAllLines 也返回 List 并一次性读入内存;它和 readString 的差别只是按行切分,不是流式。

默认编码:JDK 11 仍然是平台相关04

这是 JDK 11 最容易被忽略的编码边界:Files.readString / writeString 固定 UTF-8,但 new String(bytes)、FileReader、PrintWriter 等使用 Charset.defaultCharset()。JDK 11 的默认编码取决于操作系统和启动参数;Windows 中文环境常见 GBK。

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;

public class EncodingDemo {
    public static void main(String[] args) throws Exception {
        Path p = Path.of("cn.txt");
        Files.writeString(p, "中文");

        byte[] bytes = Files.readAllBytes(p);
        System.out.println("bytes=" + bytes.length);
        System.out.println("readString=" + Files.readString(p).length());
        System.out.println("utf8=" + new String(bytes, StandardCharsets.UTF_8).length());
        System.out.println("gbk=" + new String(bytes, Charset.forName("GBK")).length());
    }
}
bytes=6
readString=2
utf8=2
gbk=3
源码文件是 UTF-8。在中文 Windows 的 JDK 11 上编译时要显式加 javac -encoding UTF-8 EncodingDemo.java,否则编译器按 GBK 读取源文件,字面量会先被误读,再写出 9 个字节,输出就不再是下面这组值。

Files.writeString 写入 6 个 UTF-8 字节;按 UTF-8 解码得到 2 个字符,按 GBK 解码得到 3 个字符。Files.readString 的结果与 UTF-8 一致,说明它没有使用平台默认编码。

APIJDK 11 编码说明
Files.readString(Path)UTF-8严格解码,非法输入抛 MalformedInputException
Files.writeString(Path, CharSequence)UTF-8默认 CREATE / TRUNCATE_EXISTING / WRITE
new String(byte[])平台默认Windows 中文环境常见 GBK
FileReader / FileWriter平台默认JDK 11 没有无参 UTF-8 构造器
System.out平台默认重定向时尤其容易乱码
JDK 18 的 JEP 400 才把默认编码统一为 UTF-8。JDK 11 项目不要假设 Charset.defaultCharset() 是 UTF-8;跨平台读写文件时显式传 charset,或统一使用 Files 的 UTF-8 重载。

别把 12 / 15 / 18 的方法记成 1105

String 和 Files 在后续版本还在加方法。下面这些经常被误认为 JDK 11 可用,实际不在 11。

API最早版本JDK 11用途
String.isBlank / lines / strip / repeat11可用本文主题
String.indent / transform12不可用缩进、函数式转换
String.formatted15不可用格式化占位符
文本块 """15不可用多行字符串
Files.readString / writeString11可用整文件读写
Files.mismatch12不可用比较两个文件
Files.writeString 的 UTF-8 默认11可用与平台默认编码无关
// JDK 15+,JDK 11 编译失败
String json = """
        {"name": "java"}
        """;
文本块在 JDK 13/14 预览、15 正式。JDK 11 只能继续用字符串拼接、StringBuilder 或外部模板库。

版本边界BOUNDARY

这张表比 API 本身更值得记。写代码时先确认你的运行时版本。

特性 / API状态说明
String.isBlank / lines / strip / repeat11 正式不是 9/10;strip 使用 Character.isWhitespace。
Files.readString / writeString11 正式默认 UTF-8;不是平台默认编码。
Path.of11 正式替代 Paths.get。
String.transform / indent12 正式JDK 11 不可用。
String.formatted / 文本块15 正式JDK 11 不可用;文本块 13/14 预览。
默认字符集 UTF-818 正式JEP 400;JDK 11 仍平台相关。
Files.mismatch12 正式JDK 11 不可用。

费曼自检SELF CHECK

先合上页面,用自己的话回答,再展开对照。能讲出因果和反例,才算真正掌握。

01. isBlank 和 isEmpty 的区别是什么?
isEmpty 只判断长度为 0;isBlank 判断是否只包含 Character.isWhitespace 认可的空白字符。空串同时满足两者,但只含空白的字符串 isBlank 为 true、isEmpty 为 false。
02. strip 和 trim 的区别是什么?
trim 去掉首尾码点小于等于 U+0020 的字符;strip 使用 Character.isWhitespace,能处理 U+2003 等 Unicode 空白。NBSP(U+00A0)两者都不去掉。
03. Files.readString 默认用什么编码?
UTF-8。它不使用 Charset.defaultCharset();JDK 11 的默认编码仍取决于平台,JDK 18 才统一为 UTF-8。
04. Files.lines 和 String.lines 返回的 Stream 都要关闭吗?
Files.lines 持有文件句柄,必须关闭;String.lines 只是在字符串上切分,不需要关闭。Files.lines 的关闭要用 try-with-resources。
学习进度 记录保存在本机浏览器 · 不上传

JDK 学习手册 · JDK / Java 专用学习站 · 纯静态 · 双击 index.html 即可使用

本站专注 JDK 版本演进与 Java 教学,非 Oracle / OpenJDK 官方站点。版本数据来自 OpenJDK 官方 Features 表;课程示例已在对应本机 JDK 实测。构建日期 2026-11-12。