字符串与文本块
String 不可变、StringBuilder、Text Blocks、format、编码
字符串在 Java 中的特殊性
应用场景:日志消息、HTTP 请求/响应、SQL 拼接、模板渲染、CLI 参数处理。Java 的 String 设计目标是"安全 + 快"——它是不可变的、被字面量池缓存、可以作为 Map 的 key 不变质,因此在系统中流转特别频繁。
String 不可变 + 字符串字面量池
String 对象创建后内容不可修改:任何"修改"操作(replace、trim、toLowerCase…)都返回新对象。源码里相同的字面量(如 "hello")被 JVM 池化为同一对象,节省内存。new String("hello") 会强制创建新对象,绕过池——除非有特别理由,**不要 new String**。
// StringIdentity.java
public class StringIdentity {
public static void main(String[] args) {
String a = "hello";
String b = "hello"; // 同一池对象
String c = new String("hello"); // 新对象,绕过池
String d = c.intern(); // 显式入池,再次拿到池对象
System.out.println(a == b); // true(同一对象)
System.out.println(a == c); // false(c 是 new 的)
System.out.println(a == d); // true(intern 后入池)
// 永远用 equals 比较内容
System.out.println(a.equals(c)); // true
}
}StringBuilder:大量拼接必备
应用场景:循环里拼字符串、构建 CSV / SQL / 日志行。String 的 + 操作每次都生成新对象,循环里用 + 是 O(n²) 性能灾难。StringBuilder 是可变的内部缓冲区,最后一次性 toString()——性能差距能到几百倍。StringBuffer 是 StringBuilder 的线程安全版(带 synchronized),日常很少用。
// Builder.java
public class Builder {
public static void main(String[] args) {
// ❌ 错误示范:循环里用 +
// String s = "";
// for (int i = 0; i < 100_000; i++) s += i; // 极慢
// ✅ StringBuilder
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 5; i++) {
sb.append(i).append(",");
}
if (sb.length() > 0) sb.deleteCharAt(sb.length() - 1);
System.out.println(sb); // 0,1,2,3,4
// 链式 API
String json = new StringBuilder()
.append("{\"name\":\"").append("Alice").append("\",")
.append("\"age\":").append(30).append("}")
.toString();
System.out.println(json);
}
}Text Blocks 多行字符串(Java 15+)
应用场景:内嵌 SQL、JSON、HTML、SQL 模板、错误消息——以前要写一堆 \n 和转义引号,现在用三引号块。编译器自动按最左对齐位置去缩进。
// TextBlock.java
public class TextBlock {
public static void main(String[] args) {
String sql = """
SELECT id, name, email
FROM users
WHERE status = 'active'
AND created_at > ?
ORDER BY id
""";
System.out.println(sql);
String json = """
{
"name": "Alice",
"age": 30,
"tags": ["java", "go"]
}
""";
System.out.println(json);
// \<newline> 续行:拼成单行
String long1 = """
this is a very \
long single line
""";
System.out.println(long1);
}
}String.format / formatted
应用场景:构造带占位符的字符串——日志、错误消息、用户面板。printf 风格的 %s %d %.2f 等。Java 15+ 添加了实例方法 "...".formatted(args),可读性更好。
// FormatDemo.java
public class FormatDemo {
public static void main(String[] args) {
String name = "Alice";
int age = 30;
double score = 87.5;
// 经典:String.format
String s1 = String.format("%s is %d (score=%.2f)", name, age, score);
System.out.println(s1);
// Java 15+:实例方法
String s2 = "%s is %d (score=%.2f)".formatted(name, age, score);
System.out.println(s2);
// 宽度对齐、补零
System.out.println(String.format("%-10s|%5d|%08d", "id", 42, 7));
// id | 42|00000007
}
}String.join 与 split
join 把集合元素用分隔符串起来,常用于 CSV、SQL IN 列表、日志格式化。split 按正则切分。注意:split 入参是正则——切 . 要写 "\\."。
// JoinSplit.java
import java.util.List;
public class JoinSplit {
public static void main(String[] args) {
List<String> tags = List.of("java", "go", "rust");
String csv = String.join(", ", tags);
System.out.println(csv); // java, go, rust
// 构造 SQL IN 列表(实际用 PreparedStatement 占位符更安全)
String inList = String.join(",", tags);
String sql = "SELECT * FROM lang WHERE name IN (" + inList + ")";
System.out.println(sql);
// split:按正则
String line = "a, b, c , d";
String[] parts = line.split("\\s*,\\s*"); // 任意空白 + 逗号 + 任意空白
for (String p : parts) System.out.println("[" + p + "]");
// 切英文句号:需要转义
String[] segs = "www.example.com".split("\\.");
for (String s : segs) System.out.println(s);
}
}常用方法速查
// StringApi.java
public class StringApi {
public static void main(String[] args) {
String s = " Hello, Java World! ";
// 长度 / 索引访问
System.out.println(s.length());
System.out.println(s.charAt(2));
// 大小写、去空白
System.out.println(s.trim()); // 去首尾 ASCII 空白
System.out.println(s.strip()); // 去首尾 Unicode 空白(Java 11+,推荐)
System.out.println(s.toLowerCase());
System.out.println(s.toUpperCase());
// 子串与查找
System.out.println(s.substring(2, 7)); // Hello
System.out.println(s.indexOf("Java"));
System.out.println(s.contains("World"));
System.out.println(s.startsWith(" Hello"));
System.out.println(s.endsWith("! "));
// 替换
System.out.println(s.replace("World", "Universe"));
System.out.println(s.replaceAll("\\s+", "_")); // 正则替换
// 空判断
System.out.println("".isEmpty()); // true
System.out.println(" ".isBlank()); // true(Java 11+)
// 重复 (Java 11+)
System.out.println("=".repeat(10));
}
}字符串与字节(编码)
应用场景:网络收发、写文件、Base64 编码、加密哈希。String <-> byte[] 转换**必须**明确指定字符集(推荐 UTF-8),否则会用平台默认编码——在不同操作系统上行为不同,是经典的乱码源。
// Bytes.java
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
public class Bytes {
public static void main(String[] args) {
String s = "你好 Java";
// String -> byte[]
byte[] utf8 = s.getBytes(StandardCharsets.UTF_8);
byte[] gbk = s.getBytes(java.nio.charset.Charset.forName("GBK"));
System.out.println("utf8 bytes = " + utf8.length); // 11
System.out.println("gbk bytes = " + gbk.length); // 9
// byte[] -> String
String back = new String(utf8, StandardCharsets.UTF_8);
System.out.println(back);
// 16 进制查看
StringBuilder hex = new StringBuilder();
for (byte b : utf8) hex.append(String.format("%02x ", b));
System.out.println(hex);
}
}