「去除空格」聽起來簡單,實際卻有「只去首尾」「去所有空白」「合併連續空白」「保留單一空白」等細微需求差異。本文盤點 Java 8~17 四大主流做法,附效能基準與適用場景建議。
| 需求 | 範例輸入 | 期望輸出 |
|---|---|---|
| 去首尾 | " a b " | "a b" |
| 去所有空白(含 \\t \\n \\r) | "a\tb\nc" | "abc" |
| 合併連續空白為單一空格 | "a b c" | "a b c" |
| 只去除半形空格,保留換行 | "a b\nc" | "ab\nc" |
// 1. 去首尾
str.trim(); // Java 11+ 建議用 strip(),支援 Unicode 空白
str.strip(); // 推薦:含全形空白、不間斷空白等
// 2. 去所有半形空格
str.replace(" ", ""); // 字面取代,速度最快
str.replaceAll(" ", ""); // 正則,較慢但功能同
// 3. 去所有空白字元(\\s = [ \\t\\n\\x0B\\f\\r])
str.replaceAll("\\s+", ""); // 一次移除所有連續空白
import java.util.regex.*;
// 只合併連續空白為單一空格,保留換行
String s = "a b\n\n c";
s = s.replaceAll("[ \\t\\x0B\\f\\r]+", " "); // 不包含 \\n
// 輸出:"a b\n\n c"
// 完整空白字元定義(含 Unicode)
s = s.replaceAll("\\p{Space}+", " "); // Java 8+ 支援 Unicode 空白屬性
public static String collapseSpaces(String s) {
if (s == null) return null;
char[] src = s.toCharArray();
char[] dst = new char[src.length];
int write = 0;
boolean prevSpace = false;
for (char c : src) {
if (c == ' ') {
if (!prevSpace) {
dst[write++] = ' ';
prevSpace = true;
}
} else {
dst[write++] = c;
prevSpace = false;
}
}
return new String(dst, 0, write);
}
適用於高頻呼叫、大字串、Android 低記憶體環境。
// 去所有空白字元
String noSpace = str.codePoints()
.filter(cp -> !Character.isWhitespace(cp))
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
.toString();
// 合併連續空白(較複雜,建議用正則)
優點:自動處理增補字元;缺點:效能較差、語法冗長。
| 方法 | 平均耗時 (ns/op) | 備註 |
|---|---|---|
replace(" ", "") | ~45 | 最快,純字面取代 |
replaceAll("\\s+", "") | ~210 | 正則編譯開銷,可預編譯 Pattern 提升 |
Pattern.compile("\\s+").matcher(s).replaceAll("") | ~120 | 預編譯 Pattern 重複使用 |
| 手動 char[] 迴圈 | ~35 | 無物件分配,極致場景適用 |
| Stream codePoints | ~480 | 物件分配多,非熱路徑可用 |
str.strip()(Java 11+)或 str.trim()。str.replace(" ", "")。Pattern SPACE = Pattern.compile("\\s+"); SPACE.matcher(str).replaceAll("")。str.replaceAll("\\s+", " ")(含換行)或 str.replaceAll("[ \\t]+", " ")(不含換行)。char[] 迴圈或引入 Apache Commons Lang3 StringUtils(內部優化過)。replaceAll 第一參數是正則,$、\\ 需轉義。trim() 不移除全形空白 \\u3000,strip() 可。str = str.replace(...)。