CharArrayWriter 是字元導向的記憶體輸出流,繼承自 Writer。它內部維護一個動態擴充的字元陣列(char[] buf),將寫入的字元累積在記憶體中,支援轉換為字串、字元陣列,或輸出至其他 Writer。預設初始容量 32 字元,自動按 2 倍擴充。適合構建字串、產生文字報表、單元測試捕獲輸出等場景。
// 建構子
CharArrayWriter() // 預設 32 字元初始容量
CharArrayWriter(int initialSize) // 指定初始容量
// 寫入(繼承自 Writer,內部委派給 buf)
void write(int c) // 單字元
void write(char[] cbuf, int off, int len) // 字元陣列片段
void write(String str, int off, int len) // 字串片段
// Appendable 介面(支援鏈式呼叫)
CharArrayWriter append(char c)
CharArrayWriter append(CharSequence csq)
CharArrayWriter append(CharSequence csq, int start, int end)
// 狀態查詢
int size() // 目前累積字元數
char[] toCharArray() // 複製並回傳字元陣列
String toString() // 轉換為字串(等同 new String(buf, 0, count))
// 輸出至其他 Writer
void writeTo(Writer out) throws IOException
// 重置與關閉
void reset() // 清空緩衝區(count=0),容量保留
void close() // 無實際作用,標準介面相容
void flush() // 無實際作用,標準介面相容
public class CharArrayWriter extends Writer {
protected char[] buf; // 字元緩衝區
protected int count; // 有效字元數
public CharArrayWriter() {
this(32);
}
public CharArrayWriter(int initialSize) {
if (initialSize < 0) throw new IllegalArgumentException("Negative initial size");
buf = new char[initialSize];
}
// 單字元寫入:自動擴充
public void write(int c) {
synchronized (lock) {
int newCount = count + 1;
if (newCount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newCount));
}
buf[count] = (char) c;
count = newCount;
}
}
// 陣列寫入:批次複製與擴充
public void write(char[] cbuf, int off, int len) {
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
}
if (len == 0) return;
synchronized (lock) {
int newCount = count + len;
if (newCount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newCount));
}
System.arraycopy(cbuf, off, buf, count, len);
count = newCount;
}
}
// 輸出至其他 Writer
public void writeTo(Writer out) throws IOException {
synchronized (lock) {
out.write(buf, 0, count);
}
}
public void reset() {
count = 0; // 僅重置計數,陣列保留供下次複用
}
}
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.PrintWriter;
public class CharArrayWriterDemo {
public static void main(String[] args) {
demoBasicUsage();
demoTestCapture();
demoJsonBuilding();
}
// 基本用法:寫入、轉換、重置
private static void demoBasicUsage() {
CharArrayWriter caw = new CharArrayWriter(64);
caw.write('A');
caw.write("BC");
caw.write("DEFGHIJ".toCharArray(), 1, 3); // "EFG"
caw.append('0').append("123456789").append("APPEND", 2, 5); // "PPE"
System.out.println("內容: " + caw); // toString()
System.out.println("長度: " + caw.size()); // 22
System.out.println("陣列: " + new String(caw.toCharArray()));
// 複用:重置後繼續寫入
caw.reset();
caw.write("重複使用緩衝區");
System.out.println("重置後: " + caw);
}
// 單元測試:捕獲 System.out / logger 輸出
private static void demoTestCapture() {
CharArrayWriter captured = new CharArrayWriter();
PrintWriter testOut = new PrintWriter(captured);
// 模擬被測代碼寫入標準輸出
testOut.println("INFO: 服務啟動");
testOut.printf("DEBUG: 連接池大小 = %d%n", 10);
testOut.println("WARN: 配置項缺失,使用預設值");
testOut.flush();
String output = captured.toString();
System.out.println("=== 捕獲輸出 ===");
System.out.print(output);
// 斷言驗證
assert output.contains("服務啟動");
assert output.contains("連接池大小 = 10");
System.out.println("斷言通過");
}
// 手工構建 JSON(無依賴場景)
private static void demoJsonBuilding() {
CharArrayWriter caw = new CharArrayWriter(256);
caw.write('{');
appendJsonField(caw, "id", 12345);
caw.write(',');
appendJsonField(caw, "name", "產品名稱");
caw.write(',');
appendJsonField(caw, "price", 299.9);
caw.write(',');
appendJsonArray(caw, "tags", new String[]{"熱銷", "新品", "推薦"});
caw.write('}');
String json = caw.toString();
System.out.println("構建 JSON: " + json);
}
private static void appendJsonField(CharArrayWriter caw, String key, Object value) {
caw.write('"').write(key).write("\":");
if (value instanceof String) {
caw.write('"').write((String) value).write('"');
} else {
caw.write(String.valueOf(value));
}
}
private static void appendJsonArray(CharArrayWriter caw, String key, String[] values) {
caw.write('"').write(key).write("\":[");
for (int i = 0; i < values.length; i++) {
if (i > 0) caw.write(',');
caw.write('"').write(values[i]).write('"');
}
caw.write(']');
}
}
| 特性 | CharArrayWriter | StringBuilder | StringBuffer |
|---|---|---|---|
| 介面 | Writer / Appendable | Appendable / CharSequence | Appendable / CharSequence |
| 執行緒安全 | ✅ (synchronized) | ❌ | ✅ (synchronized) |
| 輸出目標 | 可 writeTo(Writer) | 僅 toString() | 僅 toString() |
| API 風格 | 流式 write/flush/close | append/insert/delete | append/insert/delete |
| 適用場景 | 需 Writer 介面、輸出轉導、測試捕獲 | 一般字串構建(單執行緒) | 多執行緒字串構建(較少用) |
| 效能 | 略低(同步開銷) | 最高 | 中等 |
initialSize 避免多次擴充複製。reset() 保留陣列容量,減少 GC 壓力。Writer 介面(如 PrintWriter、BufferedWriter、第三方庫)時,CharArrayWriter 是天然橋樑。System.setOut(new PrintWriter(charArrayWriter)) 進行單元測試斷言。StringBuilder 效能更優。close() 是空實現,reset() 才清空內容(但保留陣列),徹底釋放需讓物件失去引用等待 GC。synchronized,但複合操作(如檢查 size 再寫入)需外層同步。CharArrayWriter 是記憶體字元累積的流式工具,掌握其動態擴充、writeTo() 轉導與 reset() 複用特性,能在測試捕獲、文字報表生成、介面適配等場景發揮獨特價值。