10.1 String类详解
10.1.1 String类基础
String是Java中最常用的类之一,用于表示字符序列。String对象是不可变的(immutable),这意味着一旦创建就不能修改。
import java.util.*;
import java.util.regex.*;
import java.text.*;
import java.nio.charset.*;
/**
* String类详细演示
*/
public class StringBasicsDemo {
public static void main(String[] args) {
System.out.println("=== String类详细演示 ===");
demonstrateStringCreation();
demonstrateStringImmutability();
demonstrateStringComparison();
demonstrateStringMethods();
demonstrateStringPool();
}
public static void demonstrateStringCreation() {
System.out.println("\n--- String创建方式 ---");
// 1. 字面量创建
System.out.println("\n1. 字面量创建:");
String str1 = "Hello, World!";
String str2 = "Hello, World!";
System.out.println("str1: " + str1);
System.out.println("str2: " + str2);
System.out.println("str1 == str2: " + (str1 == str2)); // true,指向同一个对象
// 2. new关键字创建
System.out.println("\n2. new关键字创建:");
String str3 = new String("Hello, World!");
String str4 = new String("Hello, World!");
System.out.println("str3: " + str3);
System.out.println("str4: " + str4);
System.out.println("str3 == str4: " + (str3 == str4)); // false,不同对象
System.out.println("str1 == str3: " + (str1 == str3)); // false
// 3. 从字符数组创建
System.out.println("\n3. 从字符数组创建:");
char[] charArray = {'H', 'e', 'l', 'l', 'o'};
String str5 = new String(charArray);
String str6 = new String(charArray, 1, 3); // 从索引1开始,长度为3
System.out.println("从完整字符数组: " + str5);
System.out.println("从部分字符数组: " + str6);
// 4. 从字节数组创建
System.out.println("\n4. 从字节数组创建:");
byte[] byteArray = {72, 101, 108, 108, 111}; // "Hello"的ASCII码
String str7 = new String(byteArray);
String str8 = new String(byteArray, StandardCharsets.UTF_8);
System.out.println("从字节数组(默认编码): " + str7);
System.out.println("从字节数组(UTF-8编码): " + str8);
// 5. 使用StringBuilder转换
System.out.println("\n5. 使用StringBuilder转换:");
StringBuilder sb = new StringBuilder("Hello");
sb.append(", World!");
String str9 = sb.toString();
System.out.println("从StringBuilder: " + str9);
// 6. 空字符串和null
System.out.println("\n6. 空字符串和null:");
String emptyString = "";
String nullString = null;
String blankString = " ";
System.out.println("空字符串长度: " + emptyString.length());
System.out.println("空字符串是否为空: " + emptyString.isEmpty());
System.out.println("空白字符串是否为空: " + blankString.isEmpty());
System.out.println("空白字符串是否为空白: " + blankString.isBlank()); // Java 11+
// 注意:nullString.length() 会抛出NullPointerException
System.out.println("null字符串: " + nullString);
}
public static void demonstrateStringImmutability() {
System.out.println("\n--- String不可变性 ---");
System.out.println("\n1. String不可变性演示:");
String original = "Hello";
String modified = original.concat(", World!");
System.out.println("原始字符串: " + original);
System.out.println("修改后字符串: " + modified);
System.out.println("原始字符串是否改变: " + original.equals("Hello"));
// 2. 字符串操作创建新对象
System.out.println("\n2. 字符串操作创建新对象:");
String str = "Java";
System.out.println("原始字符串: " + str);
System.out.println("原始字符串hashCode: " + str.hashCode());
String upperStr = str.toUpperCase();
System.out.println("转大写后: " + upperStr);
System.out.println("转大写后hashCode: " + upperStr.hashCode());
String replacedStr = str.replace('a', 'o');
System.out.println("替换字符后: " + replacedStr);
System.out.println("替换字符后hashCode: " + replacedStr.hashCode());
// 3. 不可变性的优势
System.out.println("\n3. 不可变性的优势:");
System.out.println("- 线程安全:多个线程可以安全地访问同一个String对象");
System.out.println("- 缓存hashCode:String的hashCode只计算一次");
System.out.println("- 字符串池:相同内容的字符串可以共享内存");
System.out.println("- 安全性:字符串内容不会被意外修改");
// 4. 性能考虑
System.out.println("\n4. 性能考虑:");
demonstrateStringConcatenationPerformance();
}
private static void demonstrateStringConcatenationPerformance() {
System.out.println("\n字符串拼接性能对比:");
int iterations = 1000;
// 使用+操作符(不推荐在循环中使用)
long startTime = System.nanoTime();
String result1 = "";
for (int i = 0; i < iterations; i++) {
result1 += "a";
}
long stringConcatTime = System.nanoTime() - startTime;
// 使用StringBuilder(推荐)
startTime = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < iterations; i++) {
sb.append("a");
}
String result2 = sb.toString();
long stringBuilderTime = System.nanoTime() - startTime;
System.out.println("String +操作符: " + stringConcatTime / 1_000_000 + "ms");
System.out.println("StringBuilder: " + stringBuilderTime / 1_000_000 + "ms");
System.out.println("StringBuilder比+操作符快: " +
(stringConcatTime / (double) stringBuilderTime) + "倍");
}
public static void demonstrateStringComparison() {
System.out.println("\n--- 字符串比较 ---");
String str1 = "Hello";
String str2 = "Hello";
String str3 = new String("Hello");
String str4 = "hello";
String str5 = null;
// 1. == 比较(引用比较)
System.out.println("\n1. == 比较(引用比较):");
System.out.println("str1 == str2: " + (str1 == str2)); // true
System.out.println("str1 == str3: " + (str1 == str3)); // false
// 2. equals() 比较(内容比较)
System.out.println("\n2. equals() 比较(内容比较):");
System.out.println("str1.equals(str2): " + str1.equals(str2)); // true
System.out.println("str1.equals(str3): " + str1.equals(str3)); // true
System.out.println("str1.equals(str4): " + str1.equals(str4)); // false
System.out.println("str1.equals(str5): " + str1.equals(str5)); // false
// 3. equalsIgnoreCase() 比较(忽略大小写)
System.out.println("\n3. equalsIgnoreCase() 比较(忽略大小写):");
System.out.println("str1.equalsIgnoreCase(str4): " + str1.equalsIgnoreCase(str4)); // true
// 4. compareTo() 比较(字典序)
System.out.println("\n4. compareTo() 比较(字典序):");
System.out.println("str1.compareTo(str2): " + str1.compareTo(str2)); // 0
System.out.println("str1.compareTo(str4): " + str1.compareTo(str4)); // 负数
System.out.println("\"Apple\".compareTo(\"Banana\"): " + "Apple".compareTo("Banana")); // 负数
System.out.println("\"Zebra\".compareTo(\"Apple\"): " + "Zebra".compareTo("Apple")); // 正数
// 5. compareToIgnoreCase() 比较
System.out.println("\n5. compareToIgnoreCase() 比较:");
System.out.println("str1.compareToIgnoreCase(str4): " + str1.compareToIgnoreCase(str4)); // 0
// 6. 安全的字符串比较
System.out.println("\n6. 安全的字符串比较:");
System.out.println("Objects.equals(str1, str5): " + Objects.equals(str1, str5)); // false
System.out.println("Objects.equals(str5, str5): " + Objects.equals(str5, str5)); // true
// 避免NullPointerException的方法
System.out.println("\"Hello\".equals(str5): " + "Hello".equals(str5)); // false,安全
// str5.equals("Hello") 会抛出NullPointerException
}
public static void demonstrateStringMethods() {
System.out.println("\n--- String常用方法 ---");
String text = " Hello, Java World! Welcome to Programming. ";
// 1. 长度和字符访问
System.out.println("\n1. 长度和字符访问:");
System.out.println("原始字符串: '" + text + "'");
System.out.println("长度: " + text.length());
System.out.println("第5个字符: " + text.charAt(5));
System.out.println("字符数组: " + Arrays.toString(text.toCharArray()));
// 2. 大小写转换
System.out.println("\n2. 大小写转换:");
System.out.println("转大写: " + text.toUpperCase());
System.out.println("转小写: " + text.toLowerCase());
// 3. 去除空白
System.out.println("\n3. 去除空白:");
System.out.println("去除首尾空白: '" + text.trim() + "'");
System.out.println("去除所有空白: '" + text.strip() + "'"); // Java 11+
System.out.println("去除开头空白: '" + text.stripLeading() + "'"); // Java 11+
System.out.println("去除结尾空白: '" + text.stripTrailing() + "'"); // Java 11+
// 4. 查找和检查
System.out.println("\n4. 查找和检查:");
System.out.println("包含'Java': " + text.contains("Java"));
System.out.println("以' Hello'开头: " + text.startsWith(" Hello"));
System.out.println("以'.'结尾: " + text.endsWith("."));
System.out.println("'Java'的位置: " + text.indexOf("Java"));
System.out.println("'o'最后出现位置: " + text.lastIndexOf("o"));
System.out.println("是否为空: " + text.isEmpty());
System.out.println("是否为空白: " + text.isBlank()); // Java 11+
// 5. 子字符串
System.out.println("\n5. 子字符串:");
System.out.println("从索引7开始: '" + text.substring(7) + "'");
System.out.println("索引7到12: '" + text.substring(7, 12) + "'");
// 6. 替换
System.out.println("\n6. 替换:");
System.out.println("替换'Java'为'Python': " + text.replace("Java", "Python"));
System.out.println("替换第一个'o'为'0': " + text.replaceFirst("o", "0"));
System.out.println("替换所有'o'为'0': " + text.replaceAll("o", "0"));
// 7. 分割
System.out.println("\n7. 分割:");
String sentence = "apple,banana,orange,grape";
String[] fruits = sentence.split(",");
System.out.println("分割结果: " + Arrays.toString(fruits));
String[] limitedSplit = sentence.split(",", 2);
System.out.println("限制分割数量: " + Arrays.toString(limitedSplit));
// 8. 连接
System.out.println("\n8. 连接:");
String joined = String.join(" | ", fruits);
System.out.println("连接数组: " + joined);
List<String> list = Arrays.asList("Java", "Python", "C++", "JavaScript");
String joinedList = String.join(", ", list);
System.out.println("连接列表: " + joinedList);
// 9. 格式化
System.out.println("\n9. 格式化:");
String formatted = String.format("姓名: %s, 年龄: %d, 分数: %.2f", "张三", 25, 95.678);
System.out.println("格式化字符串: " + formatted);
// Java 15+ 文本块
System.out.println("\n10. 文本块 (Java 15+):");
String textBlock = """
这是一个文本块
可以包含多行
保持格式
""";
System.out.println("文本块: " + textBlock);
}
public static void demonstrateStringPool() {
System.out.println("\n--- 字符串池 ---");
// 1. 字符串池基础
System.out.println("\n1. 字符串池基础:");
String str1 = "Hello";
String str2 = "Hello";
String str3 = new String("Hello");
System.out.println("str1 == str2: " + (str1 == str2)); // true,来自字符串池
System.out.println("str1 == str3: " + (str1 == str3)); // false,str3在堆中
// 2. intern()方法
System.out.println("\n2. intern()方法:");
String str4 = str3.intern(); // 将str3加入字符串池
System.out.println("str1 == str4: " + (str1 == str4)); // true
// 3. 字符串池的内存优化
System.out.println("\n3. 字符串池的内存优化:");
demonstrateStringPoolMemory();
// 4. 编译时常量
System.out.println("\n4. 编译时常量:");
String compile1 = "Hello" + "World"; // 编译时连接
String compile2 = "HelloWorld";
System.out.println("编译时常量相等: " + (compile1 == compile2)); // true
String runtime1 = "Hello";
String runtime2 = runtime1 + "World"; // 运行时连接
String runtime3 = "HelloWorld";
System.out.println("运行时连接相等: " + (runtime2 == runtime3)); // false
// 5. final变量的特殊情况
System.out.println("\n5. final变量的特殊情况:");
final String finalStr = "Hello";
String combined = finalStr + "World"; // 编译时可以确定
String literal = "HelloWorld";
System.out.println("final变量连接: " + (combined == literal)); // true
}
private static void demonstrateStringPoolMemory() {
System.out.println("\n字符串池内存演示:");
// 创建大量相同的字符串
List<String> strings1 = new ArrayList<>();
List<String> strings2 = new ArrayList<>();
String commonString = "CommonString";
// 使用字符串池
for (int i = 0; i < 1000; i++) {
strings1.add(commonString); // 所有引用指向同一个对象
}
// 不使用字符串池
for (int i = 0; i < 1000; i++) {
strings2.add(new String("CommonString")); // 每次创建新对象
}
System.out.println("使用字符串池的列表大小: " + strings1.size());
System.out.println("不使用字符串池的列表大小: " + strings2.size());
// 检查引用是否相同
boolean sameReference1 = strings1.get(0) == strings1.get(999);
boolean sameReference2 = strings2.get(0) == strings2.get(999);
System.out.println("字符串池中引用相同: " + sameReference1); // true
System.out.println("堆中引用相同: " + sameReference2); // false
System.out.println("\n字符串池的优势:");
System.out.println("- 内存节省:相同内容的字符串共享内存");
System.out.println("- 比较效率:可以使用==进行快速比较");
System.out.println("- 缓存效果:常用字符串保存在池中");
}
}
10.1.2 String性能优化
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;
/**
* String性能优化演示
*/
public class StringPerformanceDemo {
public static void main(String[] args) {
System.out.println("=== String性能优化演示 ===");
demonstrateConcatenationPerformance();
demonstrateStringBuilderVsBuffer();
demonstrateStringFormatPerformance();
demonstrateStringComparisonPerformance();
demonstrateBestPractices();
}
public static void demonstrateConcatenationPerformance() {
System.out.println("\n--- 字符串拼接性能对比 ---");
int iterations = 10000;
String baseString = "Hello";
// 1. 使用+操作符
long startTime = System.nanoTime();
String result1 = "";
for (int i = 0; i < iterations; i++) {
result1 += baseString;
}
long plusOperatorTime = System.nanoTime() - startTime;
// 2. 使用StringBuilder
startTime = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < iterations; i++) {
sb.append(baseString);
}
String result2 = sb.toString();
long stringBuilderTime = System.nanoTime() - startTime;
// 3. 使用StringBuilder预分配容量
startTime = System.nanoTime();
StringBuilder sbWithCapacity = new StringBuilder(iterations * baseString.length());
for (int i = 0; i < iterations; i++) {
sbWithCapacity.append(baseString);
}
String result3 = sbWithCapacity.toString();
long stringBuilderWithCapacityTime = System.nanoTime() - startTime;
// 4. 使用StringJoiner
startTime = System.nanoTime();
StringJoiner joiner = new StringJoiner("");
for (int i = 0; i < iterations; i++) {
joiner.add(baseString);
}
String result4 = joiner.toString();
long stringJoinerTime = System.nanoTime() - startTime;
// 5. 使用Stream.collect
startTime = System.nanoTime();
String result5 = IntStream.range(0, iterations)
.mapToObj(i -> baseString)
.collect(Collectors.joining());
long streamTime = System.nanoTime() - startTime;
System.out.println("拼接" + iterations + "次字符串的性能对比:");
System.out.println("+操作符: " + plusOperatorTime / 1_000_000 + "ms");
System.out.println("StringBuilder: " + stringBuilderTime / 1_000_000 + "ms");
System.out.println("StringBuilder(预分配): " + stringBuilderWithCapacityTime / 1_000_000 + "ms");
System.out.println("StringJoiner: " + stringJoinerTime / 1_000_000 + "ms");
System.out.println("Stream.collect: " + streamTime / 1_000_000 + "ms");
System.out.println("\n性能提升倍数(相对于+操作符):");
System.out.println("StringBuilder: " + (double) plusOperatorTime / stringBuilderTime + "倍");
System.out.println("StringBuilder(预分配): " + (double) plusOperatorTime / stringBuilderWithCapacityTime + "倍");
System.out.println("StringJoiner: " + (double) plusOperatorTime / stringJoinerTime + "倍");
System.out.println("Stream.collect: " + (double) plusOperatorTime / streamTime + "倍");
// 验证结果一致性
System.out.println("\n结果一致性验证:");
System.out.println("所有结果长度相等: " +
(result1.length() == result2.length() &&
result2.length() == result3.length() &&
result3.length() == result4.length() &&
result4.length() == result5.length()));
}
public static void demonstrateStringBuilderVsBuffer() {
System.out.println("\n--- StringBuilder vs StringBuffer ---");
int iterations = 100000;
String testString = "Test";
// 1. StringBuilder(非线程安全)
long startTime = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < iterations; i++) {
sb.append(testString);
}
String result1 = sb.toString();
long stringBuilderTime = System.nanoTime() - startTime;
// 2. StringBuffer(线程安全)
startTime = System.nanoTime();
StringBuffer sbf = new StringBuffer();
for (int i = 0; i < iterations; i++) {
sbf.append(testString);
}
String result2 = sbf.toString();
long stringBufferTime = System.nanoTime() - startTime;
System.out.println("单线程性能对比:");
System.out.println("StringBuilder: " + stringBuilderTime / 1_000_000 + "ms");
System.out.println("StringBuffer: " + stringBufferTime / 1_000_000 + "ms");
System.out.println("StringBuilder比StringBuffer快: " +
(double) stringBufferTime / stringBuilderTime + "倍");
// 3. 多线程环境测试
System.out.println("\n多线程环境测试:");
demonstrateMultiThreadedStringBuilding();
}
private static void demonstrateMultiThreadedStringBuilding() {
int threadCount = 10;
int iterationsPerThread = 1000;
// StringBuilder(非线程安全)
StringBuilder unsafeSb = new StringBuilder();
ExecutorService executor1 = Executors.newFixedThreadPool(threadCount);
long startTime = System.nanoTime();
for (int i = 0; i < threadCount; i++) {
executor1.submit(() -> {
for (int j = 0; j < iterationsPerThread; j++) {
unsafeSb.append("A");
}
});
}
executor1.shutdown();
try {
executor1.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
long unsafeTime = System.nanoTime() - startTime;
// StringBuffer(线程安全)
StringBuffer safeSbf = new StringBuffer();
ExecutorService executor2 = Executors.newFixedThreadPool(threadCount);
startTime = System.nanoTime();
for (int i = 0; i < threadCount; i++) {
executor2.submit(() -> {
for (int j = 0; j < iterationsPerThread; j++) {
safeSbf.append("A");
}
});
}
executor2.shutdown();
try {
executor2.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
long safeTime = System.nanoTime() - startTime;
System.out.println("多线程环境性能:");
System.out.println("StringBuilder(非线程安全): " + unsafeTime / 1_000_000 + "ms");
System.out.println("StringBuffer(线程安全): " + safeTime / 1_000_000 + "ms");
int expectedLength = threadCount * iterationsPerThread;
System.out.println("\n结果验证:");
System.out.println("期望长度: " + expectedLength);
System.out.println("StringBuilder实际长度: " + unsafeSb.length() +
(unsafeSb.length() == expectedLength ? " ✓" : " ✗ (数据竞争)"));
System.out.println("StringBuffer实际长度: " + safeSbf.length() +
(safeSbf.length() == expectedLength ? " ✓" : " ✗"));
}
public static void demonstrateStringFormatPerformance() {
System.out.println("\n--- 字符串格式化性能 ---");
int iterations = 100000;
String name = "张三";
int age = 25;
double score = 95.67;
// 1. String.format()
long startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
String result = String.format("姓名: %s, 年龄: %d, 分数: %.2f", name, age, score);
}
long formatTime = System.nanoTime() - startTime;
// 2. StringBuilder拼接
startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
StringBuilder sb = new StringBuilder();
sb.append("姓名: ").append(name)
.append(", 年龄: ").append(age)
.append(", 分数: ").append(String.format("%.2f", score));
String result = sb.toString();
}
long stringBuilderTime = System.nanoTime() - startTime;
// 3. 简单字符串拼接
startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
String result = "姓名: " + name + ", 年龄: " + age + ", 分数: " +
String.format("%.2f", score);
}
long concatenationTime = System.nanoTime() - startTime;
// 4. MessageFormat
MessageFormat messageFormat = new MessageFormat("姓名: {0}, 年龄: {1}, 分数: {2,number,#.##}");
startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
String result = messageFormat.format(new Object[]{name, age, score});
}
long messageFormatTime = System.nanoTime() - startTime;
System.out.println("格式化" + iterations + "次字符串的性能对比:");
System.out.println("String.format(): " + formatTime / 1_000_000 + "ms");
System.out.println("StringBuilder: " + stringBuilderTime / 1_000_000 + "ms");
System.out.println("字符串拼接: " + concatenationTime / 1_000_000 + "ms");
System.out.println("MessageFormat: " + messageFormatTime / 1_000_000 + "ms");
System.out.println("\n性能排序(从快到慢):");
Map<String, Long> results = new HashMap<>();
results.put("StringBuilder", stringBuilderTime);
results.put("字符串拼接", concatenationTime);
results.put("String.format()", formatTime);
results.put("MessageFormat", messageFormatTime);
results.entrySet().stream()
.sorted(Map.Entry.comparingByValue())
.forEach(entry -> System.out.println(entry.getKey() + ": " +
entry.getValue() / 1_000_000 + "ms"));
}
public static void demonstrateStringComparisonPerformance() {
System.out.println("\n--- 字符串比较性能 ---");
int iterations = 1000000;
String str1 = "Hello, World!";
String str2 = "Hello, World!";
String str3 = new String("Hello, World!");
String str4 = "HELLO, WORLD!";
// 1. == 比较
long startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
boolean result = str1 == str2;
}
long referenceComparisonTime = System.nanoTime() - startTime;
// 2. equals() 比较
startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
boolean result = str1.equals(str3);
}
long equalsTime = System.nanoTime() - startTime;
// 3. equalsIgnoreCase() 比较
startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
boolean result = str1.equalsIgnoreCase(str4);
}
long equalsIgnoreCaseTime = System.nanoTime() - startTime;
// 4. compareTo() 比较
startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
int result = str1.compareTo(str3);
}
long compareToTime = System.nanoTime() - startTime;
System.out.println("比较" + iterations + "次字符串的性能对比:");
System.out.println("== 引用比较: " + referenceComparisonTime / 1_000_000 + "ms");
System.out.println("equals() 内容比较: " + equalsTime / 1_000_000 + "ms");
System.out.println("equalsIgnoreCase(): " + equalsIgnoreCaseTime / 1_000_000 + "ms");
System.out.println("compareTo(): " + compareToTime / 1_000_000 + "ms");
System.out.println("\n性能提升倍数(相对于equals):");
System.out.println("== 比equals快: " + (double) equalsTime / referenceComparisonTime + "倍");
System.out.println("equals比equalsIgnoreCase快: " +
(double) equalsIgnoreCaseTime / equalsTime + "倍");
System.out.println("equals比compareTo快: " + (double) compareToTime / equalsTime + "倍");
}
public static void demonstrateBestPractices() {
System.out.println("\n--- String性能最佳实践 ---");
System.out.println("\n1. 字符串拼接最佳实践:");
System.out.println("✓ 少量拼接:使用+操作符");
System.out.println("✓ 循环拼接:使用StringBuilder");
System.out.println("✓ 大量拼接:预分配StringBuilder容量");
System.out.println("✓ 多线程拼接:使用StringBuffer或ThreadLocal<StringBuilder>");
System.out.println("\n2. 字符串比较最佳实践:");
System.out.println("✓ 引用比较:使用==(仅限字符串池中的字符串)");
System.out.println("✓ 内容比较:使用equals()");
System.out.println("✓ 忽略大小写:使用equalsIgnoreCase()");
System.out.println("✓ 避免NullPointerException:使用Objects.equals()或常量.equals(变量)");
System.out.println("\n3. 字符串创建最佳实践:");
System.out.println("✓ 优先使用字面量:利用字符串池");
System.out.println("✓ 避免不必要的new String()");
System.out.println("✓ 使用intern()谨慎:只对重复使用的字符串");
System.out.println("\n4. 内存优化最佳实践:");
System.out.println("✓ 及时释放大字符串的引用");
System.out.println("✓ 使用substring()时注意内存泄漏(Java 7之前)");
System.out.println("✓ 考虑使用char[]代替String处理敏感数据");
System.out.println("\n5. 格式化最佳实践:");
System.out.println("✓ 简单格式化:使用StringBuilder");
System.out.println("✓ 复杂格式化:使用String.format()");
System.out.println("✓ 重复格式化:缓存MessageFormat实例");
System.out.println("✓ 国际化:使用MessageFormat");
// 演示最佳实践示例
demonstrateBestPracticeExamples();
}
private static void demonstrateBestPracticeExamples() {
System.out.println("\n--- 最佳实践示例 ---");
// 1. 正确的字符串拼接
System.out.println("\n1. 正确的字符串拼接:");
// 少量拼接
String simple = "Hello" + ", " + "World!";
System.out.println("简单拼接: " + simple);
// 循环拼接
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 5; i++) {
sb.append("Item ").append(i).append("; ");
}
System.out.println("循环拼接: " + sb.toString());
// 预分配容量
List<String> items = Arrays.asList("Apple", "Banana", "Orange", "Grape");
StringBuilder sbWithCapacity = new StringBuilder(items.size() * 10); // 估算容量
for (String item : items) {
sbWithCapacity.append(item).append(", ");
}
System.out.println("预分配容量: " + sbWithCapacity.toString());
// 2. 安全的字符串比较
System.out.println("\n2. 安全的字符串比较:");
String nullableString = null;
String constantString = "Hello";
// 安全的比较方式
System.out.println("安全比较1: " + Objects.equals(nullableString, constantString));
System.out.println("安全比较2: " + constantString.equals(nullableString));
// 3. 高效的字符串处理
System.out.println("\n3. 高效的字符串处理:");
String text = " Hello, World! ";
// 链式调用
String processed = text.trim().toLowerCase().replace("world", "java");
System.out.println("链式处理: " + processed);
// 使用Stream处理字符串集合
List<String> words = Arrays.asList("apple", "banana", "ORANGE", "grape");
String result = words.stream()
.map(String::toLowerCase)
.filter(word -> word.length() > 4)
.collect(Collectors.joining(", "));
System.out.println("Stream处理: " + result);
}
}
10.2 StringBuilder和StringBuffer
10.2.1 StringBuilder详解
import java.util.*;
import java.util.stream.*;
/**
* StringBuilder详细演示
*/
public class StringBuilderDemo {
public static void main(String[] args) {
System.out.println("=== StringBuilder详细演示 ===");
demonstrateStringBuilderBasics();
demonstrateStringBuilderMethods();
demonstrateStringBuilderCapacity();
demonstrateStringBuilderPerformance();
demonstrateStringBuilderUseCases();
}
public static void demonstrateStringBuilderBasics() {
System.out.println("\n--- StringBuilder基础 ---");
// 1. 创建StringBuilder的不同方式
System.out.println("\n1. 创建StringBuilder:");
// 默认构造器(初始容量16)
StringBuilder sb1 = new StringBuilder();
System.out.println("默认构造器容量: " + sb1.capacity());
// 指定初始容量
StringBuilder sb2 = new StringBuilder(50);
System.out.println("指定容量构造器: " + sb2.capacity());
// 从字符串创建
StringBuilder sb3 = new StringBuilder("Hello");
System.out.println("从字符串创建: '" + sb3.toString() + "', 容量: " + sb3.capacity());
// 从CharSequence创建
StringBuilder sb4 = new StringBuilder(sb3);
System.out.println("从CharSequence创建: '" + sb4.toString() + "'");
// 2. StringBuilder的可变性
System.out.println("\n2. StringBuilder的可变性:");
StringBuilder mutableSb = new StringBuilder("Original");
System.out.println("原始内容: " + mutableSb.toString());
System.out.println("原始hashCode: " + mutableSb.hashCode());
mutableSb.append(" Modified");
System.out.println("修改后内容: " + mutableSb.toString());
System.out.println("修改后hashCode: " + mutableSb.hashCode()); // 注意:可能相同或不同
// 3. StringBuilder vs String
System.out.println("\n3. StringBuilder vs String:");
demonstrateStringBuilderVsString();
}
private static void demonstrateStringBuilderVsString() {
System.out.println("\nStringBuilder vs String 对比:");
int iterations = 1000;
// String拼接
long startTime = System.nanoTime();
String str = "";
for (int i = 0; i < iterations; i++) {
str += "a";
}
long stringTime = System.nanoTime() - startTime;
// StringBuilder拼接
startTime = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < iterations; i++) {
sb.append("a");
}
String sbResult = sb.toString();
long sbTime = System.nanoTime() - startTime;
System.out.println("String拼接时间: " + stringTime / 1_000_000 + "ms");
System.out.println("StringBuilder拼接时间: " + sbTime / 1_000_000 + "ms");
System.out.println("StringBuilder比String快: " + (double) stringTime / sbTime + "倍");
System.out.println("结果长度相等: " + (str.length() == sbResult.length()));
}
public static void demonstrateStringBuilderMethods() {
System.out.println("\n--- StringBuilder方法详解 ---");
StringBuilder sb = new StringBuilder("Hello");
// 1. 追加方法
System.out.println("\n1. 追加方法:");
System.out.println("初始内容: '" + sb.toString() + "'");
sb.append(", World!");
System.out.println("append(String): '" + sb.toString() + "'");
sb.append(' ').append(123).append(' ').append(45.67);
System.out.println("链式append: '" + sb.toString() + "'");
sb.append(true).append(' ').append('X');
System.out.println("append多种类型: '" + sb.toString() + "'");
// append数组
char[] chars = {'A', 'B', 'C'};
sb.append(' ').append(chars);
System.out.println("append字符数组: '" + sb.toString() + "'");
sb.append(' ').append(chars, 1, 2); // 从索引1开始,长度为2
System.out.println("append部分字符数组: '" + sb.toString() + "'");
// 2. 插入方法
System.out.println("\n2. 插入方法:");
sb = new StringBuilder("Hello World");
System.out.println("原始: '" + sb.toString() + "'");
sb.insert(5, ", Beautiful");
System.out.println("insert(5, String): '" + sb.toString() + "'");
sb.insert(0, "Say: ");
System.out.println("insert(0, String): '" + sb.toString() + "'");
sb.insert(sb.length(), "!");
System.out.println("insert(end, String): '" + sb.toString() + "'");
// 3. 删除方法
System.out.println("\n3. 删除方法:");
sb = new StringBuilder("Hello, Beautiful World!");
System.out.println("原始: '" + sb.toString() + "'");
sb.delete(5, 17); // 删除", Beautiful"
System.out.println("delete(5, 17): '" + sb.toString() + "'");
sb.deleteCharAt(5); // 删除逗号
System.out.println("deleteCharAt(5): '" + sb.toString() + "'");
// 4. 替换方法
System.out.println("\n4. 替换方法:");
sb = new StringBuilder("Hello World");
System.out.println("原始: '" + sb.toString() + "'");
sb.replace(6, 11, "Java");
System.out.println("replace(6, 11, 'Java'): '" + sb.toString() + "'");
// 5. 反转方法
System.out.println("\n5. 反转方法:");
sb = new StringBuilder("Hello");
System.out.println("原始: '" + sb.toString() + "'");
sb.reverse();
System.out.println("reverse(): '" + sb.toString() + "'");
// 6. 查找方法
System.out.println("\n6. 查找方法:");
sb = new StringBuilder("Hello World Hello");
System.out.println("内容: '" + sb.toString() + "'");
System.out.println("indexOf('o'): " + sb.indexOf("o"));
System.out.println("lastIndexOf('o'): " + sb.lastIndexOf("o"));
System.out.println("indexOf('Hello', 1): " + sb.indexOf("Hello", 1));
// 7. 字符访问和修改
System.out.println("\n7. 字符访问和修改:");
sb = new StringBuilder("Hello");
System.out.println("原始: '" + sb.toString() + "'");
System.out.println("charAt(1): " + sb.charAt(1));
sb.setCharAt(1, 'a');
System.out.println("setCharAt(1, 'a'): '" + sb.toString() + "'");
// 8. 子序列方法
System.out.println("\n8. 子序列方法:");
sb = new StringBuilder("Hello World");
System.out.println("原始: '" + sb.toString() + "'");
CharSequence subSeq = sb.subSequence(6, 11);
System.out.println("subSequence(6, 11): '" + subSeq.toString() + "'");
String substring = sb.substring(6);
System.out.println("substring(6): '" + substring + "'");
String substring2 = sb.substring(0, 5);
System.out.println("substring(0, 5): '" + substring2 + "'");
}
public static void demonstrateStringBuilderCapacity() {
System.out.println("\n--- StringBuilder容量管理 ---");
// 1. 容量的基本概念
System.out.println("\n1. 容量基本概念:");
StringBuilder sb = new StringBuilder();
System.out.println("初始容量: " + sb.capacity());
System.out.println("初始长度: " + sb.length());
sb.append("Hello");
System.out.println("添加'Hello'后容量: " + sb.capacity());
System.out.println("添加'Hello'后长度: " + sb.length());
// 2. 容量扩展机制
System.out.println("\n2. 容量扩展机制:");
sb = new StringBuilder(10);
System.out.println("初始容量: " + sb.capacity());
// 添加字符直到超过容量
for (int i = 0; i < 15; i++) {
sb.append('a');
if (i == 9 || i == 14) {
System.out.println("长度" + sb.length() + "时容量: " + sb.capacity());
}
}
// 3. 手动容量管理
System.out.println("\n3. 手动容量管理:");
sb = new StringBuilder("Hello");
System.out.println("原始容量: " + sb.capacity());
sb.ensureCapacity(50);
System.out.println("ensureCapacity(50)后: " + sb.capacity());
sb.trimToSize();
System.out.println("trimToSize()后: " + sb.capacity());
System.out.println("当前长度: " + sb.length());
// 4. 容量对性能的影响
System.out.println("\n4. 容量对性能的影响:");
demonstrateCapacityPerformance();
// 5. 设置长度
System.out.println("\n5. 设置长度:");
sb = new StringBuilder("Hello World");
System.out.println("原始: '" + sb.toString() + "', 长度: " + sb.length());
sb.setLength(5);
System.out.println("setLength(5): '" + sb.toString() + "', 长度: " + sb.length());
sb.setLength(10);
System.out.println("setLength(10): '" + sb.toString() + "', 长度: " + sb.length());
System.out.println("注意:扩展部分用\\0填充");
}
private static void demonstrateCapacityPerformance() {
int iterations = 10000;
String testString = "Test";
// 不预分配容量
long startTime = System.nanoTime();
StringBuilder sb1 = new StringBuilder();
for (int i = 0; i < iterations; i++) {
sb1.append(testString);
}
long noPreallocationTime = System.nanoTime() - startTime;
// 预分配容量
startTime = System.nanoTime();
StringBuilder sb2 = new StringBuilder(iterations * testString.length());
for (int i = 0; i < iterations; i++) {
sb2.append(testString);
}
long preallocationTime = System.nanoTime() - startTime;
System.out.println("不预分配容量: " + noPreallocationTime / 1_000_000 + "ms");
System.out.println("预分配容量: " + preallocationTime / 1_000_000 + "ms");
System.out.println("预分配比不预分配快: " +
(double) noPreallocationTime / preallocationTime + "倍");
}
public static void demonstrateStringBuilderPerformance() {
System.out.println("\n--- StringBuilder性能特性 ---");
// 1. 不同操作的性能
System.out.println("\n1. 不同操作的性能对比:");
int iterations = 100000;
// append性能
StringBuilder sb = new StringBuilder(iterations * 5);
long startTime = System.nanoTime();
for (int i = 0; i < iterations; i++) {
sb.append("test");
}
long appendTime = System.nanoTime() - startTime;
// insert性能(在开头插入)
sb = new StringBuilder(iterations * 5);
startTime = System.nanoTime();
for (int i = 0; i < 1000; i++) { // 减少迭代次数,因为insert较慢
sb.insert(0, "test");
}
long insertTime = System.nanoTime() - startTime;
// delete性能
sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
sb.append("test");
}
startTime = System.nanoTime();
for (int i = 0; i < 500; i++) {
if (sb.length() >= 4) {
sb.delete(0, 4);
}
}
long deleteTime = System.nanoTime() - startTime;
System.out.println("append " + iterations + "次: " + appendTime / 1_000_000 + "ms");
System.out.println("insert 1000次: " + insertTime / 1_000_000 + "ms");
System.out.println("delete 500次: " + deleteTime / 1_000_000 + "ms");
// 2. 内存使用分析
System.out.println("\n2. 内存使用分析:");
demonstrateMemoryUsage();
}
private static void demonstrateMemoryUsage() {
System.out.println("\nStringBuilder内存使用分析:");
// 创建不同大小的StringBuilder
StringBuilder small = new StringBuilder("Hello");
StringBuilder medium = new StringBuilder(1000);
StringBuilder large = new StringBuilder(10000);
System.out.println("小StringBuilder - 长度: " + small.length() + ", 容量: " + small.capacity());
System.out.println("中StringBuilder - 长度: " + medium.length() + ", 容量: " + medium.capacity());
System.out.println("大StringBuilder - 长度: " + large.length() + ", 容量: " + large.capacity());
// 演示容量浪费
StringBuilder wasteful = new StringBuilder(1000);
wasteful.append("Small content");
System.out.println("\n容量浪费示例:");
System.out.println("分配容量: " + wasteful.capacity());
System.out.println("实际使用: " + wasteful.length());
System.out.println("浪费比例: " + (1.0 - (double)wasteful.length() / wasteful.capacity()) * 100 + "%");
wasteful.trimToSize();
System.out.println("trimToSize后容量: " + wasteful.capacity());
}
public static void demonstrateStringBuilderUseCases() {
System.out.println("\n--- StringBuilder使用场景 ---");
// 1. 动态SQL构建
System.out.println("\n1. 动态SQL构建:");
String sql = buildDynamicSQL("users",
Arrays.asList("name", "age", "email"),
Arrays.asList("age > 18", "status = 'active'"));
System.out.println("动态SQL: " + sql);
// 2. CSV数据生成
System.out.println("\n2. CSV数据生成:");
List<String[]> data = Arrays.asList(
new String[]{"张三", "25", "工程师"},
new String[]{"李四", "30", "设计师"},
new String[]{"王五", "28", "产品经理"}
);
String csv = generateCSV(Arrays.asList("姓名", "年龄", "职位"), data);
System.out.println("CSV数据:\n" + csv);
// 3. HTML生成
System.out.println("\n3. HTML生成:");
String html = generateHTMLTable(Arrays.asList("姓名", "年龄", "职位"), data);
System.out.println("HTML表格:\n" + html);
// 4. 日志格式化
System.out.println("\n4. 日志格式化:");
String log = formatLogMessage("INFO", "UserService", "用户登录成功",
Map.of("userId", "12345", "ip", "192.168.1.1"));
System.out.println("格式化日志: " + log);
// 5. JSON构建(简单版)
System.out.println("\n5. 简单JSON构建:");
String json = buildSimpleJSON(Map.of(
"name", "张三",
"age", "25",
"active", "true"
));
System.out.println("JSON: " + json);
// 6. 字符串模板
System.out.println("\n6. 字符串模板:");
String template = "Hello, {name}! You have {count} new messages.";
String result = processTemplate(template, Map.of("name", "张三", "count", "5"));
System.out.println("模板结果: " + result);
}
private static String buildDynamicSQL(String table, List<String> columns, List<String> conditions) {
StringBuilder sql = new StringBuilder();
// SELECT子句
sql.append("SELECT ");
sql.append(String.join(", ", columns));
// FROM子句
sql.append(" FROM ").append(table);
// WHERE子句
if (!conditions.isEmpty()) {
sql.append(" WHERE ");
sql.append(String.join(" AND ", conditions));
}
return sql.toString();
}
private static String generateCSV(List<String> headers, List<String[]> data) {
StringBuilder csv = new StringBuilder();
// 添加标题行
csv.append(String.join(",", headers)).append("\n");
// 添加数据行
for (String[] row : data) {
csv.append(String.join(",", row)).append("\n");
}
return csv.toString();
}
private static String generateHTMLTable(List<String> headers, List<String[]> data) {
StringBuilder html = new StringBuilder();
html.append("<table border='1'>\n");
// 标题行
html.append(" <thead>\n <tr>\n");
for (String header : headers) {
html.append(" <th>").append(header).append("</th>\n");
}
html.append(" </tr>\n </thead>\n");
// 数据行
html.append(" <tbody>\n");
for (String[] row : data) {
html.append(" <tr>\n");
for (String cell : row) {
html.append(" <td>").append(cell).append("</td>\n");
}
html.append(" </tr>\n");
}
html.append(" </tbody>\n");
html.append("</table>");
return html.toString();
}
private static String formatLogMessage(String level, String component, String message, Map<String, String> context) {
StringBuilder log = new StringBuilder();
log.append("[").append(new Date()).append("] ");
log.append("[").append(level).append("] ");
log.append("[").append(component).append("] ");
log.append(message);
if (!context.isEmpty()) {
log.append(" - ");
context.forEach((key, value) ->
log.append(key).append("=").append(value).append(", "));
// 移除最后的逗号和空格
log.setLength(log.length() - 2);
}
return log.toString();
}
private static String buildSimpleJSON(Map<String, String> data) {
StringBuilder json = new StringBuilder();
json.append("{");
boolean first = true;
for (Map.Entry<String, String> entry : data.entrySet()) {
if (!first) {
json.append(", ");
}
json.append('"').append(entry.getKey()).append('"');
json.append(": ");
// 简单的值处理(实际应用中需要更复杂的转义)
String value = entry.getValue();
if ("true".equals(value) || "false".equals(value) || value.matches("\\d+")) {
json.append(value);
} else {
json.append('"').append(value).append('"');
}
first = false;
}
json.append("}");
return json.toString();
}
private static String processTemplate(String template, Map<String, String> variables) {
StringBuilder result = new StringBuilder(template);
for (Map.Entry<String, String> entry : variables.entrySet()) {
String placeholder = "{" + entry.getKey() + "}";
int index = result.indexOf(placeholder);
while (index != -1) {
result.replace(index, index + placeholder.length(), entry.getValue());
index = result.indexOf(placeholder, index + entry.getValue().length());
}
}
return result.toString();
}
}
10.2.2 StringBuffer详解
import java.util.concurrent.*;
import java.util.*;
/**
* StringBuffer详细演示
*/
public class StringBufferDemo {
public static void main(String[] args) {
System.out.println("=== StringBuffer详细演示 ===");
demonstrateStringBufferBasics();
demonstrateThreadSafety();
demonstrateStringBufferVsStringBuilder();
demonstrateStringBufferUseCases();
}
public static void demonstrateStringBufferBasics() {
System.out.println("\n--- StringBuffer基础 ---");
// 1. StringBuffer的创建
System.out.println("\n1. StringBuffer创建:");
StringBuffer sb1 = new StringBuffer();
System.out.println("默认构造器容量: " + sb1.capacity());
StringBuffer sb2 = new StringBuffer(50);
System.out.println("指定容量构造器: " + sb2.capacity());
StringBuffer sb3 = new StringBuffer("Hello");
System.out.println("从字符串创建: '" + sb3.toString() + "', 容量: " + sb3.capacity());
// 2. 基本操作
System.out.println("\n2. 基本操作:");
StringBuffer sb = new StringBuffer("Hello");
System.out.println("初始: '" + sb.toString() + "'");
sb.append(", World!");
System.out.println("append后: '" + sb.toString() + "'");
sb.insert(5, " Beautiful");
System.out.println("insert后: '" + sb.toString() + "'");
sb.delete(5, 15);
System.out.println("delete后: '" + sb.toString() + "'");
sb.reverse();
System.out.println("reverse后: '" + sb.toString() + "'");
// 3. StringBuffer的同步特性
System.out.println("\n3. StringBuffer的同步特性:");
System.out.println("StringBuffer的所有方法都是synchronized的");
System.out.println("这保证了线程安全,但也带来了性能开销");
// 查看方法签名(通过反射)
demonstrateStringBufferSynchronization();
}
private static void demonstrateStringBufferSynchronization() {
System.out.println("\nStringBuffer方法同步验证:");
try {
Class<?> sbClass = StringBuffer.class;
// 检查几个主要方法是否为synchronized
String[] methodNames = {"append", "insert", "delete", "reverse", "toString"};
for (String methodName : methodNames) {
try {
var methods = sbClass.getDeclaredMethods();
boolean foundSynchronized = false;
for (var method : methods) {
if (method.getName().equals(methodName)) {
int modifiers = method.getModifiers();
if (java.lang.reflect.Modifier.isSynchronized(modifiers)) {
foundSynchronized = true;
break;
}
}
}
System.out.println(methodName + "方法是否synchronized: " + foundSynchronized);
} catch (Exception e) {
System.out.println(methodName + "方法检查失败: " + e.getMessage());
}
}
} catch (Exception e) {
System.out.println("反射检查失败: " + e.getMessage());
}
}
public static void demonstrateThreadSafety() {
System.out.println("\n--- 线程安全演示 ---");
int threadCount = 10;
int operationsPerThread = 1000;
// 1. StringBuffer线程安全测试
System.out.println("\n1. StringBuffer线程安全测试:");
StringBuffer safeBuffer = new StringBuffer();
ExecutorService executor1 = Executors.newFixedThreadPool(threadCount);
CountDownLatch latch1 = new CountDownLatch(threadCount);
long startTime = System.nanoTime();
for (int i = 0; i < threadCount; i++) {
final int threadId = i;
executor1.submit(() -> {
try {
for (int j = 0; j < operationsPerThread; j++) {
safeBuffer.append("T" + threadId + "_" + j + ";");
}
} finally {
latch1.countDown();
}
});
}
try {
latch1.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
long safeTime = System.nanoTime() - startTime;
executor1.shutdown();
// 2. StringBuilder非线程安全对比
System.out.println("\n2. StringBuilder非线程安全对比:");
StringBuilder unsafeBuilder = new StringBuilder();
ExecutorService executor2 = Executors.newFixedThreadPool(threadCount);
CountDownLatch latch2 = new CountDownLatch(threadCount);
startTime = System.nanoTime();
for (int i = 0; i < threadCount; i++) {
final int threadId = i;
executor2.submit(() -> {
try {
for (int j = 0; j < operationsPerThread; j++) {
unsafeBuilder.append("T" + threadId + "_" + j + ";");
}
} finally {
latch2.countDown();
}
});
}
try {
latch2.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
long unsafeTime = System.nanoTime() - startTime;
executor2.shutdown();
// 3. 结果分析
System.out.println("\n3. 结果分析:");
int expectedLength = threadCount * operationsPerThread;
// 计算实际操作数(通过分号数量)
int safeOperations = safeBuffer.toString().split(";").length - 1;
int unsafeOperations = unsafeBuilder.toString().split(";").length - 1;
System.out.println("期望操作数: " + expectedLength);
System.out.println("StringBuffer实际操作数: " + safeOperations +
(safeOperations == expectedLength ? " ✓" : " ✗"));
System.out.println("StringBuilder实际操作数: " + unsafeOperations +
(unsafeOperations == expectedLength ? " ✓" : " ✗ (数据竞争)"));
System.out.println("\nStringBuffer执行时间: " + safeTime / 1_000_000 + "ms");
System.out.println("StringBuilder执行时间: " + unsafeTime / 1_000_000 + "ms");
if (unsafeTime > 0) {
System.out.println("StringBuilder比StringBuffer快: " +
(double) safeTime / unsafeTime + "倍(但不安全)");
}
}
public static void demonstrateStringBufferVsStringBuilder() {
System.out.println("\n--- StringBuffer vs StringBuilder详细对比 ---");
// 1. 功能对比
System.out.println("\n1. 功能对比:");
System.out.println("StringBuffer:");
System.out.println(" - 线程安全(synchronized方法)");
System.out.println(" - 性能较低(同步开销)");
System.out.println(" - 适用于多线程环境");
System.out.println(" - JDK 1.0引入");
System.out.println("\nStringBuilder:");
System.out.println(" - 非线程安全");
System.out.println(" - 性能较高(无同步开销)");
System.out.println(" - 适用于单线程环境");
System.out.println(" - JDK 1.5引入");
// 2. 性能对比
System.out.println("\n2. 单线程性能对比:");
performSingleThreadComparison();
// 3. API兼容性
System.out.println("\n3. API兼容性:");
demonstrateAPICompatibility();
// 4. 使用建议
System.out.println("\n4. 使用建议:");
System.out.println("✓ 单线程环境:优先使用StringBuilder");
System.out.println("✓ 多线程环境:使用StringBuffer或ThreadLocal<StringBuilder>");
System.out.println("✓ 性能敏感场景:考虑使用StringBuilder + 外部同步");
System.out.println("✓ 遗留代码:StringBuffer可以直接替换为StringBuilder(注意线程安全)");
}
private static void performSingleThreadComparison() {
int iterations = 100000;
String testString = "Test";
// StringBuffer测试
long startTime = System.nanoTime();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < iterations; i++) {
sb.append(testString);
}
String result1 = sb.toString();
long stringBufferTime = System.nanoTime() - startTime;
// StringBuilder测试
startTime = System.nanoTime();
StringBuilder sbd = new StringBuilder();
for (int i = 0; i < iterations; i++) {
sbd.append(testString);
}
String result2 = sbd.toString();
long stringBuilderTime = System.nanoTime() - startTime;
System.out.println("StringBuffer时间: " + stringBufferTime / 1_000_000 + "ms");
System.out.println("StringBuilder时间: " + stringBuilderTime / 1_000_000 + "ms");
System.out.println("StringBuilder比StringBuffer快: " +
(double) stringBufferTime / stringBuilderTime + "倍");
System.out.println("结果一致: " + result1.equals(result2));
}
private static void demonstrateAPICompatibility() {
System.out.println("\nAPI兼容性演示:");
// 两者具有相同的API
StringBuffer sb = new StringBuffer("Hello");
StringBuilder sbd = new StringBuilder("Hello");
// 相同的方法调用
sb.append(", World!").insert(5, " Beautiful").reverse();
sbd.append(", World!").insert(5, " Beautiful").reverse();
System.out.println("StringBuffer结果: " + sb.toString());
System.out.println("StringBuilder结果: " + sbd.toString());
System.out.println("结果相同: " + sb.toString().equals(sbd.toString()));
// 都实现了相同的接口
System.out.println("\n接口实现:");
System.out.println("StringBuffer实现Appendable: " + (sb instanceof Appendable));
System.out.println("StringBuilder实现Appendable: " + (sbd instanceof Appendable));
System.out.println("StringBuffer实现CharSequence: " + (sb instanceof CharSequence));
System.out.println("StringBuilder实现CharSequence: " + (sbd instanceof CharSequence));
}
public static void demonstrateStringBufferUseCases() {
System.out.println("\n--- StringBuffer使用场景 ---");
// 1. 多线程日志收集
System.out.println("\n1. 多线程日志收集:");
demonstrateMultiThreadedLogging();
// 2. 线程安全的缓存构建
System.out.println("\n2. 线程安全的缓存构建:");
demonstrateThreadSafeCache();
// 3. 替代方案:ThreadLocal<StringBuilder>
System.out.println("\n3. 替代方案:ThreadLocal<StringBuilder>:");
demonstrateThreadLocalAlternative();
}
private static void demonstrateMultiThreadedLogging() {
StringBuffer logBuffer = new StringBuffer();
int threadCount = 5;
int logsPerThread = 3;
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
CountDownLatch latch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
final int threadId = i;
executor.submit(() -> {
try {
for (int j = 0; j < logsPerThread; j++) {
String logEntry = String.format("[Thread-%d] Log entry %d at %s\n",
threadId, j, new Date());
logBuffer.append(logEntry);
// 模拟一些处理时间
try {
Thread.sleep(10);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
} finally {
latch.countDown();
}
});
}
try {
latch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
executor.shutdown();
System.out.println("多线程日志收集结果:");
System.out.println(logBuffer.toString());
// 验证日志完整性
String[] lines = logBuffer.toString().split("\n");
System.out.println("总日志条数: " + lines.length +
" (期望: " + (threadCount * logsPerThread) + ")");
}
private static void demonstrateThreadSafeCache() {
// 简单的线程安全缓存实现
class ThreadSafeStringCache {
private final StringBuffer cache = new StringBuffer();
private final Set<String> keys = ConcurrentHashMap.newKeySet();
public void addEntry(String key, String value) {
if (keys.add(key)) { // 避免重复
cache.append(key).append("=").append(value).append(";");
}
}
public String getCache() {
return cache.toString();
}
public int size() {
return keys.size();
}
}
ThreadSafeStringCache cache = new ThreadSafeStringCache();
int threadCount = 3;
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
CountDownLatch latch = new CountDownLatch(threadCount);
for (int i = 0; i < threadCount; i++) {
final int threadId = i;
executor.submit(() -> {
try {
for (int j = 0; j < 5; j++) {
cache.addEntry("key_" + threadId + "_" + j, "value_" + threadId + "_" + j);
}
} finally {
latch.countDown();
}
});
}
try {
latch.await();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
executor.shutdown();
System.out.println("线程安全缓存结果:");
System.out.println("缓存内容: " + cache.getCache());
System.out.println("缓存条目数: " + cache.size());
}
private static void demonstrateThreadLocalAlternative() {
// ThreadLocal<StringBuilder>作为StringBuffer的替代方案
ThreadLocal<StringBuilder> threadLocalBuilder = ThreadLocal.withInitial(StringBuilder::new);
class ThreadLocalStringProcessor {
public String processInCurrentThread(String... inputs) {
StringBuilder sb = threadLocalBuilder.get();
sb.setLength(0); // 清空之前的内容
for (String input : inputs) {
sb.append("[").append(Thread.currentThread().getName()).append("] ")
.append(input).append("\n");
}
return sb.toString();
}
}
ThreadLocalStringProcessor processor = new ThreadLocalStringProcessor();
// 在不同线程中使用
ExecutorService executor = Executors.newFixedThreadPool(3);
List<Future<String>> futures = new ArrayList<>();
for (int i = 0; i < 3; i++) {
final int threadId = i;
Future<String> future = executor.submit(() ->
processor.processInCurrentThread("Message 1 from thread " + threadId,
"Message 2 from thread " + threadId));
futures.add(future);
}
System.out.println("ThreadLocal<StringBuilder>结果:");
for (int i = 0; i < futures.size(); i++) {
try {
System.out.println("Thread " + i + " result:\n" + futures.get(i).get());
} catch (Exception e) {
System.err.println("获取结果失败: " + e.getMessage());
}
}
executor.shutdown();
System.out.println("ThreadLocal优势:");
System.out.println("- 每个线程有独立的StringBuilder实例");
System.out.println("- 无需同步,性能更好");
System.out.println("- 避免线程间的竞争");
System.out.println("- 注意:需要及时清理避免内存泄漏");
}
}
10.3 正则表达式
10.3.1 正则表达式基础
import java.util.regex.*;
import java.util.*;
/**
* 正则表达式基础演示
*/
public class RegexBasicsDemo {
public static void main(String[] args) {
System.out.println("=== 正则表达式基础演示 ===");
demonstrateRegexBasics();
demonstratePatternAndMatcher();
demonstrateCommonPatterns();
demonstrateRegexFlags();
demonstrateStringRegexMethods();
}
public static void demonstrateRegexBasics() {
System.out.println("\n--- 正则表达式基础 ---");
// 1. 基本概念
System.out.println("\n1. 基本概念:");
System.out.println("正则表达式(Regular Expression)是用于匹配字符串模式的强大工具");
System.out.println("Java中主要通过Pattern和Matcher类来使用正则表达式");
// 2. 基本字符匹配
System.out.println("\n2. 基本字符匹配:");
String text = "Hello World 123";
System.out.println("文本: " + text);
System.out.println("匹配'Hello': " + text.matches(".*Hello.*"));
System.out.println("匹配'hello'(忽略大小写): " +
Pattern.compile(".*hello.*", Pattern.CASE_INSENSITIVE).matcher(text).matches());
// 3. 元字符介绍
System.out.println("\n3. 常用元字符:");
System.out.println(". - 匹配任意单个字符(除换行符)");
System.out.println("* - 匹配前面的字符0次或多次");
System.out.println("+ - 匹配前面的字符1次或多次");
System.out.println("? - 匹配前面的字符0次或1次");
System.out.println("^ - 匹配字符串开始");
System.out.println("$ - 匹配字符串结束");
System.out.println("[] - 字符类,匹配括号内的任意字符");
System.out.println("() - 分组");
System.out.println("| - 或操作");
System.out.println("\\ - 转义字符");
// 4. 简单示例
System.out.println("\n4. 简单示例:");
demonstrateBasicExamples();
}
private static void demonstrateBasicExamples() {
String[] texts = {"cat", "bat", "rat", "hat", "dog", "car"};
String pattern = "[cbr]at"; // 匹配cat, bat, rat
System.out.println("模式: " + pattern);
System.out.println("测试文本: " + Arrays.toString(texts));
Pattern p = Pattern.compile(pattern);
for (String text : texts) {
boolean matches = p.matcher(text).matches();
System.out.println("'" + text + "' 匹配: " + matches);
}
}
public static void demonstratePatternAndMatcher() {
System.out.println("\n--- Pattern和Matcher类 ---");
// 1. Pattern类
System.out.println("\n1. Pattern类:");
String regex = "\\d{3}-\\d{3}-\\d{4}"; // 电话号码格式
Pattern pattern = Pattern.compile(regex);
System.out.println("编译的正则表达式: " + pattern.pattern());
System.out.println("标志位: " + pattern.flags());
// 2. Matcher类
System.out.println("\n2. Matcher类:");
String text = "我的电话是123-456-7890,办公电话是987-654-3210";
Matcher matcher = pattern.matcher(text);
System.out.println("文本: " + text);
System.out.println("查找所有匹配:");
while (matcher.find()) {
System.out.println("找到: " + matcher.group() +
" 位置: " + matcher.start() + "-" + matcher.end());
}
// 3. 重置Matcher
System.out.println("\n3. 重置Matcher:");
matcher.reset();
System.out.println("重置后查找第一个匹配: " + matcher.find());
if (matcher.find()) {
System.out.println("第一个匹配: " + matcher.group());
}
// 4. 替换操作
System.out.println("\n4. 替换操作:");
matcher.reset();
String replaced = matcher.replaceAll("XXX-XXX-XXXX");
System.out.println("替换后: " + replaced);
matcher.reset();
String replacedFirst = matcher.replaceFirst("[隐藏]");
System.out.println("只替换第一个: " + replacedFirst);
}
public static void demonstrateCommonPatterns() {
System.out.println("\n--- 常用正则表达式模式 ---");
// 定义常用模式
Map<String, String> patterns = new LinkedHashMap<>();
patterns.put("邮箱", "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}");
patterns.put("手机号", "1[3-9]\\d{9}");
patterns.put("身份证", "\\d{17}[\\dXx]");
patterns.put("IP地址", "((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)\\.){3}(25[0-5]|2[0-4]\\d|[01]?\\d\\d?)");
patterns.put("URL", "https?://[\\w\\-]+(\\.[\\w\\-]+)+([\\w\\-\\.,@?^=%&:/~\\+#]*[\\w\\-\\@?^=%&/~\\+#])?");
patterns.put("日期(yyyy-mm-dd)", "\\d{4}-\\d{2}-\\d{2}");
patterns.put("时间(hh:mm:ss)", "([01]?\\d|2[0-3]):[0-5]\\d:[0-5]\\d");
patterns.put("中文字符", "[\\u4e00-\\u9fa5]+");
patterns.put("数字(整数)", "-?\\d+");
patterns.put("数字(小数)", "-?\\d+(\\.\\d+)?");
// 测试数据
Map<String, String[]> testData = new HashMap<>();
testData.put("邮箱", new String[]{"user@example.com", "test.email+tag@domain.co.uk", "invalid.email"});
testData.put("手机号", new String[]{"13812345678", "15987654321", "12345678901"});
testData.put("身份证", new String[]{"123456789012345678", "12345678901234567X", "1234567890"});
testData.put("IP地址", new String[]{"192.168.1.1", "255.255.255.255", "256.1.1.1"});
testData.put("URL", new String[]{"https://www.example.com", "http://test.com/path?param=value", "ftp://invalid"});
testData.put("日期(yyyy-mm-dd)", new String[]{"2023-12-25", "2023-02-29", "23-12-25"});
testData.put("时间(hh:mm:ss)", new String[]{"14:30:45", "23:59:59", "25:00:00"});
testData.put("中文字符", new String[]{"你好世界", "Hello世界", "123"});
testData.put("数字(整数)", new String[]{"123", "-456", "12.34"});
testData.put("数字(小数)", new String[]{"123.45", "-67.89", "abc"});
// 测试每个模式
for (Map.Entry<String, String> entry : patterns.entrySet()) {
String name = entry.getKey();
String regex = entry.getValue();
String[] tests = testData.get(name);
System.out.println("\n" + name + " 模式: " + regex);
if (tests != null) {
Pattern pattern = Pattern.compile(regex);
for (String test : tests) {
boolean matches = pattern.matcher(test).matches();
System.out.println(" '" + test + "' -> " + (matches ? "✓" : "✗"));
}
}
}
}
public static void demonstrateRegexFlags() {
System.out.println("\n--- 正则表达式标志位 ---");
String text = "Hello\nWORLD\nJava";
System.out.println("测试文本: " + text.replace("\n", "\\n"));
// 1. CASE_INSENSITIVE - 忽略大小写
System.out.println("\n1. CASE_INSENSITIVE - 忽略大小写:");
Pattern pattern1 = Pattern.compile("hello", Pattern.CASE_INSENSITIVE);
System.out.println("模式'hello'(忽略大小写)匹配: " + pattern1.matcher(text).find());
Pattern pattern2 = Pattern.compile("hello");
System.out.println("模式'hello'(区分大小写)匹配: " + pattern2.matcher(text).find());
// 2. MULTILINE - 多行模式
System.out.println("\n2. MULTILINE - 多行模式:");
Pattern pattern3 = Pattern.compile("^WORLD$", Pattern.MULTILINE);
System.out.println("多行模式下'^WORLD$'匹配: " + pattern3.matcher(text).find());
Pattern pattern4 = Pattern.compile("^WORLD$");
System.out.println("单行模式下'^WORLD$'匹配: " + pattern4.matcher(text).find());
// 3. DOTALL - 点号匹配所有字符
System.out.println("\n3. DOTALL - 点号匹配所有字符:");
Pattern pattern5 = Pattern.compile("Hello.*Java", Pattern.DOTALL);
System.out.println("DOTALL模式下'Hello.*Java'匹配: " + pattern5.matcher(text).find());
Pattern pattern6 = Pattern.compile("Hello.*Java");
System.out.println("普通模式下'Hello.*Java'匹配: " + pattern6.matcher(text).find());
// 4. 组合标志位
System.out.println("\n4. 组合标志位:");
Pattern pattern7 = Pattern.compile("hello.*java",
Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
System.out.println("组合标志位'hello.*java'匹配: " + pattern7.matcher(text).find());
// 5. 在正则表达式中使用标志位
System.out.println("\n5. 在正则表达式中使用标志位:");
Pattern pattern8 = Pattern.compile("(?i)hello.*(?s)java"); // (?i)忽略大小写,(?s)点号匹配所有
System.out.println("内联标志位'(?i)hello.*(?s)java'匹配: " + pattern8.matcher(text).find());
// 6. 所有标志位说明
System.out.println("\n6. 所有标志位说明:");
System.out.println("CASE_INSENSITIVE (2): 忽略大小写");
System.out.println("MULTILINE (8): ^和$匹配行的开始和结束");
System.out.println("DOTALL (32): .匹配包括换行符在内的所有字符");
System.out.println("UNICODE_CASE (64): 与CASE_INSENSITIVE一起使用,支持Unicode");
System.out.println("CANON_EQ (128): 考虑Unicode规范等价");
System.out.println("UNIX_LINES (1): 只有\\n被认为是行终止符");
System.out.println("LITERAL (16): 将模式作为字面量处理");
System.out.println("UNICODE_CHARACTER_CLASS (256): 启用Unicode字符类");
System.out.println("COMMENTS (4): 允许在模式中使用空白和注释");
}
public static void demonstrateStringRegexMethods() {
System.out.println("\n--- String类的正则表达式方法 ---");
String text = "Java is great, Java is powerful, Java is everywhere!";
System.out.println("原始文本: " + text);
// 1. matches() - 完全匹配
System.out.println("\n1. matches() - 完全匹配:");
System.out.println("完全匹配'Java.*': " + text.matches("Java.*"));
System.out.println("完全匹配'.*Java.*': " + text.matches(".*Java.*"));
// 2. split() - 分割字符串
System.out.println("\n2. split() - 分割字符串:");
String[] parts1 = text.split(", ");
System.out.println("按', '分割: " + Arrays.toString(parts1));
String[] parts2 = text.split("\\s+"); // 按空白字符分割
System.out.println("按空白字符分割: " + Arrays.toString(parts2));
String[] parts3 = text.split("Java");
System.out.println("按'Java'分割: " + Arrays.toString(parts3));
// 限制分割数量
String[] parts4 = text.split(", ", 2);
System.out.println("限制分割为2部分: " + Arrays.toString(parts4));
// 3. replaceAll() - 替换所有匹配
System.out.println("\n3. replaceAll() - 替换所有匹配:");
String replaced1 = text.replaceAll("Java", "Python");
System.out.println("替换'Java'为'Python': " + replaced1);
String replaced2 = text.replaceAll("\\bis\\b", "was"); // 单词边界
System.out.println("替换单词'is'为'was': " + replaced2);
// 4. replaceFirst() - 替换第一个匹配
System.out.println("\n4. replaceFirst() - 替换第一个匹配:");
String replaced3 = text.replaceFirst("Java", "Python");
System.out.println("只替换第一个'Java': " + replaced3);
// 5. 复杂的替换示例
System.out.println("\n5. 复杂的替换示例:");
String phoneText = "联系电话:123-456-7890 或 987-654-3210";
System.out.println("原始: " + phoneText);
// 使用分组进行替换
String maskedPhone = phoneText.replaceAll("(\\d{3})-(\\d{3})-(\\d{4})", "$1-XXX-$3");
System.out.println("掩码中间部分: " + maskedPhone);
// 6. 实用示例
System.out.println("\n6. 实用示例:");
demonstrateStringRegexExamples();
}
private static void demonstrateStringRegexExamples() {
// 清理HTML标签
String html = "<p>这是一个<strong>重要</strong>的<em>消息</em>。</p>";
String cleanText = html.replaceAll("<[^>]+>", "");
System.out.println("清理HTML: " + html + " -> " + cleanText);
// 提取数字
String mixedText = "价格是$123.45,折扣10%,总计$111.11";
String[] numbers = mixedText.split("[^\\d.]+");
System.out.println("提取数字: " + mixedText);
System.out.println("数字: " + Arrays.toString(Arrays.stream(numbers)
.filter(s -> !s.isEmpty() && s.matches("\\d+(\\.\\d+)?"))
.toArray()));
// 验证邮箱格式
String[] emails = {"user@example.com", "invalid.email", "test@domain.co.uk"};
String emailPattern = "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}";
System.out.println("\n邮箱验证:");
for (String email : emails) {
boolean valid = email.matches(emailPattern);
System.out.println(email + " -> " + (valid ? "有效" : "无效"));
}
// 格式化文本
String messyText = " hello world java ";
String formatted = messyText.trim().replaceAll("\\s+", " ");
System.out.println("\n格式化文本: '" + messyText + "' -> '" + formatted + "'");
}
}