1. 使用原生 Java 实现
在不引入第三方库的情况下,直接用 JDK 自带的 API 将 Reader
转成 String
是基础功。这里有两个常见写法:逐字符读取和批量读取。
✅ 方式一:逐字符读取(适用于小数据量)
简单粗暴,但性能较差,尤其是数据量大时,字符串频繁拼接会触发多次对象创建,不推荐用于生产环境。
@Test
public void givenUsingPlainJava_whenConvertingReaderIntoStringV1_thenCorrect()
throws IOException {
StringReader reader = new StringReader("Hello, Baeldung!");
int intValueOfChar;
String targetString = "";
while ((intValueOfChar = reader.read()) != -1) {
targetString += (char) intValueOfChar;
}
reader.close();
assertEquals("Hello, Baeldung!", targetString);
}
⚠️ 踩坑提醒:String += char
在循环中会产生大量临时对象,GC 压力大。
✅ 方式二:批量读取 + StringBuilder(推荐)
使用固定大小的字符数组批量读取,配合 StringBuilder
避免重复创建字符串对象,性能更好,适合处理大文本。
@Test
public void givenUsingPlainJava_whenConvertingReaderIntoStringV2_thenCorrect()
throws IOException {
Reader initialReader = new StringReader("This is a longer text for testing.");
char[] arr = new char[8 * 1024]; // 8KB 缓冲区
StringBuilder buffer = new StringBuilder();
int numCharsRead;
while ((numCharsRead = initialReader.read(arr, 0, arr.length)) != -1) {
buffer.append(arr, 0, numCharsRead);
}
initialReader.close();
String targetString = buffer.toString();
assertEquals("This is a longer text for testing.", targetString);
}
📌 核心要点:
- 缓冲区大小建议设为 8KB(常见 I/O 块大小)
- 使用
StringBuilder
而非StringBuffer
(单线程无需同步开销)
2. 使用 Guava
Google Guava 提供了非常简洁的工具类 CharStreams
,一行代码搞定转换,代码可读性强,推荐在使用 Guava 的项目中采用。
@Test
public void givenUsingGuava_whenConvertingReaderIntoString_thenCorrect()
throws IOException {
Reader initialReader = CharSource.wrap("With Google Guava").openStream();
String targetString = CharStreams.toString(initialReader);
initialReader.close();
assertEquals("With Google Guava", targetString);
}
✅ 优点:
- API 简洁,语义清晰
- 内部已做性能优化(使用缓冲)
❌ 注意:
- 需要引入
com.google.guava:guava
依赖 CharSource.wrap().openStream()
返回的是Reader
,别忘了关闭资源(或用 try-with-resources)
📌 建议用 try-with-resources 更安全:
try (Reader reader = CharSource.wrap("With Google Guava").openStream()) {
String result = CharStreams.toString(reader);
}
3. 使用 Apache Commons IO
Apache Commons IO 是 Java 项目中最常用的 I/O 工具库之一,IOUtils.toString()
方法广为人知,简单直接,生态支持好。
@Test
public void givenUsingCommonsIO_whenConvertingReaderIntoString_thenCorrect()
throws IOException {
Reader initialReader = new StringReader("With Apache Commons IO");
String targetString = IOUtils.toString(initialReader);
initialReader.close();
assertEquals("With Apache Commons IO", targetString);
}
✅ 优点:
- 方法名直观,易于理解
- 社区广泛,几乎成为事实标准
- 支持重载方法指定字符编码(如
IOUtils.toString(Reader, Charset)
)
❌ 注意:
- 自 2.6 版本起,
IOUtils
中部分方法已标记为过期,推荐使用IOUtils.toString(Reader)
或迁移到commons-io-2.11+
的新 API - 同样需要注意资源关闭
📌 推荐写法(自动资源管理):
try (Reader reader = new StringReader("With Apache Commons IO")) {
String result = IOUtils.toString(reader);
}
总结对比
方式 | 是否需要依赖 | 性能 | 可读性 | 推荐场景 |
---|---|---|---|---|
原生 Java(逐字符) ❌ | 否 | ⭐☆☆ | ⭐☆☆ | 仅学习用途 |
原生 Java(批量) ✅ | 否 | ⭐⭐⭐ | ⭐⭐☆ | 无依赖项目,需控制体积 |
Guava ✅ | 是 | ⭐⭐⭐ | ⭐⭐⭐ | 已使用 Guava 的项目 |
Commons IO ✅ | 是 | ⭐⭐⭐ | ⭐⭐⭐ | 主流选择,兼容性好 |
📌 最终建议:
- 如果项目已经引入 Guava 或 Commons IO,优先使用对应工具方法
- 否则,使用原生 Java 的批量读取方案,避免性能陷阱
- ⚠️ 所有
Reader
操作务必注意资源释放,推荐统一使用try-with-resources