我們使用 AI 服務時,經常遇到一個問題:回傳的文字格式不規範。比如,我們期望得到一個乾淨的 JSON 文字,但實際收到的可能是這樣:
String aiResponse = """
{
"name": "张三",
"message": "Hello\\nWorld"
}
""";
這段文字前後有多餘的空行,內部還有 \n
這樣的轉義字元。直接使用會導致程式出錯。
過去的處理方式
在 Java 11 之前,清理這類文字通常有兩種方式:- 引入第三方函式庫:比如 Apache Commons Lang,增加了專案的複雜度。
- 手寫複雜的程式碼:用迴圈和判斷條件,寫很多行程式碼來處理各種情況。
這兩種方式效率都不高,程式碼也不夠簡潔。
現代 Java 的解決方案
現在,Java 自身內建了強大的文字處理方法。我們不再需要外部函式庫或複雜的程式碼。 使用新方法有三個直接的好處:
- 零依賴:Java 原生支援,專案更輕量。
- 程式碼更少:過去 5 行程式碼的工作,現在 1 行就能完成。
- 可讀性好:程式碼像一篇流暢的英文,邏輯清晰。
下面我們介紹 9 個核心的新方法。
核心方法詳解
1. isBlank()
- 檢查字串是否為空白
// 傳統方式
String str = " ";
boolean isEmpty = str.trim().isEmpty(); // 繁瑣
// 現代方式
boolean isBlank = str.isBlank(); // 簡潔明瞭
在驗證使用者輸入時,這個方法非常有用。
public boolean isValidUsername(String username) {
return username != null && !username.isBlank();
}
2. lines()
– 逐行處理文字
這個方法能把一大段文字,一行行分開進行處理,方便過濾或進行映射(map)操作。
String text = """
第一行
第二行
第三行
""";
text.lines()
.filter(line -> !line.isBlank())
.map(String::trim)
.forEach(System.out::println);
3. repeat(int count)
- 重複字串
需要產生一條分隔線,或者增加縮排時,這個方法很方便。
之前:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++) {
sb.append("=");
}
String separator = sb.toString();
- 現在:
String separator = "=".repeat(10);
一行程式碼就代替了 4 行迴圈,非常清晰。
4. strip()
系列 - 清除空白
strip()
可以清除字串兩端的所有類型的空白字元,包括 Unicode 空白,比舊的 trim()
方法更強大。
String unicode = "\u2000Hello\u2000"; // \u2000 是一个 Unicode 空格
unicode.trim(); // 無法去除
unicode.strip(); // 正確去除
strip()
: 清除兩端空白
stripLeading()
: 清除開頭空白
stripTrailing()
: 清除結尾空白
5. indent(int n)
- 調整縮排
為文字的每一行增加或減少指定數量的空格。在格式化程式碼、JSON 或 XML 時很有用。
String code = """
public void hello() {
System.out.println("Hello");
}
""";
// 增加 4 個空格縮排
String indented = code.indent(4);
// 減少 2 個空格縮排
String dedented = code.indent(-2);
6. transform(Function)
- 鏈式轉換
這個方法允許我們把一連串的處理操作,用流暢的鏈式方式寫出來,避免了中間變數。
String result = "hello"
.transform(String::toUpperCase)
.transform(s -> s + " WORLD");
// 結果: "HELLO WORLD"
7. formatted(Object... args)
- 格式化文字
它是靜態方法 String.format()
的實體版本,不會打斷鏈式呼叫。
之前: String message = String.format("Hello, %s", name);
現在: String message = "Hello, %s".formatted(name);
鏈式呼叫範例:
String report = """
用户: %s
餘額: %.2f
狀態: %s
"""
.formatted(username, balance, status)
.transform(String::strip);
8. stripIndent()
- 移除共同的縮排
在處理多行文字區塊時,這個方法可以智慧地移除每一行共有的前置空白。
public String generateSQL() {
return """
SELECT id, name
FROM users
WHERE status = 'active'
""".stripIndent();
}
這樣得到的 SQL 文字就會從第一列開始,沒有多餘的縮排。
9. translateEscapes()
- 處理轉義字元
這個方法將文字中的 \n
、\t
等轉義字元,直接轉換為它們所代表的實際字元。
String escaped = "Hello\\nWorld\\tJava";
String translated = escaped.translateEscapes();
System.out.println(escaped); // Hello\nWorld\tJava
System.out.println(translated); // Hello
// World Java
常見轉義序列:
- \n - 換行符
- \t - 定位字元 (Tab)
- \r - 歸位字元 (Carriage Return)
- \\ - 反斜線
- \" - 雙引號
- \' - 單引號
應用場景:
- 處理設定檔中的轉義字元
- 解析使用者輸入的轉義序列
- 處理 JSON 字串
public String processConfigValue(String value) {
return value
.strip()
.translateEscapes();
}
實戰案例:AI Json Repair
public class PromptBuilder {
/**
* 建構結構化的 AI 提示詞
*/
public String buildPrompt(String role, String task, List<String> examples) {
String exampleSection = examples.stream()
.map("- %s"::formatted)
.collect(Collectors.joining("\n"))
.indent(2);
return """
Role: %s
Task:
%s
Examples:
%s
Please provide your response in JSON format.
""".formatted(role, task.indent(2).strip(), exampleSection)
.stripIndent();
}
/**
* 清理 AI 回傳的結果
*/
public String cleanAIResponse(String aiOutput) {
return aiOutput
.strip() // 去除首尾空白
.lines() // 按行處理
.map(String::strip) // 去除每行空白
.filter(line -> !line.isBlank()) // 過濾空行
.filter(line -> !line.startsWith("```")) // 去除程式碼區塊標記
.collect(Collectors.joining("\n"))
.translateEscapes(); // 處理轉義字元
}
/**
* 提取 AI 回傳的 JSON 內容
*/
public String extractJson(String aiResponse) {
List<String> lines = aiResponse.lines()
.dropWhile(line -> !line.strip().startsWith("{")) // 跳到 JSON 開始
.toList();
// 找到第一個以 } 結尾的行的索引(包含該行)
int endIndex = 0;
for (int i = 0; i < lines.size(); i++) {
if (lines.get(i).strip().endsWith("}")) {
endIndex = i + 1; // +1 是因為 subList 的 toIndex 是不包含自身的
break;
}
}
return String.join("\n", lines.subList(0, endIndex))
.transform(this::cleanAIResponse);
}
}
使用範例:
void main() {
PromptBuilder builder = new PromptBuilder();
// 1. 建構提示詞
String prompt = builder.buildPrompt(
"Java Expert",
"Generate a User entity class with validation",
List.of(
"Include id, name, email fields",
"Add Jakarta validation annotations",
"Use Lombok annotations"
)
);
System.out.println("=== 傳送給 AI 的提示詞 ===");
System.out.println(prompt);
// 2. 模擬 AI 回傳的不規範輸出
String aiResponse = """
Sure! Here's the code:
```java
{
"className": "User",
"fields": "id, name, email"
}
```
Hope this helps!
""";
// 3. 清理 AI 輸出
String cleaned = builder.cleanAIResponse(aiResponse);
System.out.println("\n=== 清理後的結果 ===");
System.out.println(cleaned);
// 4. 提取 JSON
String json = builder.extractJson(aiResponse);
System.out.println("\n=== 提取的 JSON ===");
System.out.println(json);
}
輸出結果:
=== 傳送給 AI 的提示詞 ===
Role: Java Expert
Task:
Generate a User entity class with validation
Examples:
- Include id, name, email fields
- Add Jakarta validation annotations
- Use Lombok annotations
Please provide your response in JSON format.
=== 清理後的結果 ===
Sure! Here's the code:
{
"className": "User",
"fields": "id, name, email"
}
Hope this helps!
=== 提取的 JSON ===
{
"className": "User",
"fields": "id, name, email"
}
組合使用:30 秒清理 AI 回應
回到開頭的例子,我們可以把這些方法組合起來,建構一個高效的清理流程。
public String cleanAIResponse(String aiOutput) {
return aiOutput
.strip() // 1. 清除首尾空白
.translateEscapes() // 2. 將 \n 等轉為實際換行
.lines() // 3. 按行切分
.filter(line -> !line.isBlank()) // 4. 過濾掉完全是空白的行
.collect(Collectors.joining("\n")); // 5. 重新組合成一個字串
}
這個流程不到 30 秒就能寫完,而且能穩定地處理各種不規範的文字輸入。
現在就去試試
這些現代 Java 的 String
方法,讓我們的文字處理程式碼變得更簡潔、更穩定,可讀性也更高。 打開我們的專案,找到一段處理字串的程式碼,看看能否用這些新方法來優化它。快來試試吧!
小弟創建了一個有關ClaudeCode以及寫程式碼的DC群組,目前還處於起步狀態,希望各位能多多支持!每天都會在群組裏分享ClaudeCode的使用技巧。如果大家感興趣,請點按ClaudeCode交流群組加入!感激不盡。