Java字符串处理:String、StringBuilder与StringBuffer
目录
1. String类
1.1 基本特性
1.2 常用操作方法
2. StringBuffer类
2.1 基本特性
2.2 append方法
3. StringBuilder类
3.1 基本特性
4. 性能对比
4.1 单线程性能测试
4.2 多线程安全性测试
StringBuffer线程安全测试:
StringBuilder线程不安全测试:
5. 字符串去重问题
1. String类
1.1 基本特性
String类被设计为final类,这意味着它不能被继承。
设计为final类是为了不希望子类去重写父类的方法。
Java使用字符串池来优化字符串内存使用。
String s1 = "123";
String s2 = new String("123");String s3 = s1.intern(); // 返回字符串在常量池中的引用System.out.println(s1 == s3); // true,因为都指向常量池中的同一个对象
System.out.println(s1.equals(s3)); // true,内容相同
字符串不可变性
String对象一旦创建就不能被修改,所有看似修改的操作实际上都是创建新的String对象。
public class Test1 {String str = "1234"; // 在字符串池中创建"1234"public void change(String str){
// this.str = "456"; // 直接修改成员变量str ="456"; // 在字符串池中创建新的"456"对象,str引用指向新对象。方法内的str参数只是外部t.str引用的一个副本。}public static void main(String[] args) { Test1 t = new Test1();t.change(t.str);System.out.println(t.str); // 1234}
}
1.2 常用操作方法
// 长度获取
System.out.println(s1.length()); // 方法:字符串长度用length()方法
int[] as = new int[10];
System.out.println(as.length);//属性:数组长度用length属性 // 去除空格
String s4 = " 123 ";
System.out.println(s4.trim()); // 123
System.out.println(s4.length()); // 7
System.out.println(s4.trim().length()); //3String s5 = " 12 3 ";
System.out.println(s5.trim().length()); // 8
String result ="";
char[] cs = s5.toCharArray(); // 把一个字符串转换成数组
for(char c:cs)
{if(c>= '0' && c <='9'){result+=String.valueOf(c); }}
System.out.println(result); // 123// 字符定位和查找
String s6 = "123456";
System.out.println(s6.charAt(0)); // '1',获取指定位置的字符
System.out.println(s6.indexOf("5")); // 4,查找字符位置// 邮箱格式验证示例
String s7 = "lixin@qq.com";
System.out.println(s7.indexOf(".") > 0 && s7.indexOf("@") > 0);// 截取操作
String s8 = "a.txt.txt";
System.out.println(s8.substring(s8.lastIndexOf("."), s8.length())); // .txt
System.out.println(s8.startsWith("a")); // true
System.out.println(s8.endsWith(".txt")); // true// 分割字符串
String s9 = "13913321086,13913321087,13913321086";
String[] strs = s9.split(",");
for(String s : strs) {System.out.println(s);
}// 替换操作
String str = "美味的炸鸡腿";
String result1 = str.replaceFirst("美味的", "***");
System.out.println(result1); // ***炸鸡腿// 字符串格式化和连接
String str1 = String.format("你好,%s,%s", "哈哈", "五哈");
System.out.println(str1); // 你好,哈哈",五哈String str3 = str1.concat("23");
System.out.println(str3); // 你好,哈哈",五哈23
2. StringBuffer类
2.1 基本特性
StringBuffer是可变的字符序列,线程安全。
//JDK1.4
public class Test { public static void main(String[] args) {StringBuffer sb1 = new StringBuffer("123"); StringBuffer sb2 = new StringBuffer("123");System.out.println(sb1 == sb2); //false//StringBuffer没有重写Object的equals()方法,Object的equals()默认比较的是内存地址(引用相等).System.out.println(sb1.equals(sb2)); //falseSystem.out.println(sb1.append(true)); //123trueSystem.out.println(sb1); //123trueSystem.out.println(sb1.insert(0, "6")); //6123true}}
2.2 append方法
append()是StringBuffer类中最核心和常用的方法,是线程安全的,用于向字符串缓冲区追加内容。返回StringBuffer本身。
StringBuffer sb = new StringBuffer();// 追加各种类型数据
sb.append("Hello"); // 追加字符串
sb.append(' '); // 追加字符
sb.append(123); // 追加整数
sb.append(true); // 追加布尔值
sb.append(45.67); // 追加浮点数System.out.println(sb.toString()); // Hello 123true45.67
3. StringBuilder类
3.1 基本特性
StringBuilder也是可变的字符序列,但不是线程安全的。
StringBuilder sb1 = new StringBuilder("123");
StringBuilder sb2 = new StringBuilder("123");System.out.println(sb1 == sb2); // false
System.out.println(sb1.equals(sb2)); // falseSystem.out.println(sb1.append(true)); // 123true
System.out.println(sb1.insert(0, "6")); // 6123true
4. 性能对比
4.1 单线程性能测试
public class Test {public static void test1(long size, String str) {StringBuffer sb = new StringBuffer();long startTime = System.currentTimeMillis();for (int i = 0; i < size; i++) {sb.append(str);}long endTime = System.currentTimeMillis();System.out.println("StringBuffer的拼接字符串的时间为:" + (endTime - startTime));}public static void test2(long size, String str) {StringBuilder sb = new StringBuilder();long startTime = System.currentTimeMillis();for (int i = 0; i < size; i++) {sb.append(str);}long endTime = System.currentTimeMillis();System.out.println("StringBuilder的拼接字符串的时间为:" + (endTime - startTime));}public static void main(String[] args) {long size = 3000000;String str = "123456";
public class Test {public static void test1(long size, String str) {StringBuffer sb = new StringBuffer();long startTime = System.currentTimeMillis();for (int i = 0; i < size; i++) {sb.append(str);}long endTime = System.currentTimeMillis();System.out.println("StringBuffer的拼接字符串的时间为:" + (endTime - startTime));}public static void test2(long size, String str) {StringBuilder sb = new StringBuilder();long startTime = System.currentTimeMillis();for (int i = 0; i < size; i++) {sb.append(str);}long endTime = System.currentTimeMillis();System.out.println("StringBuilder的拼接字符串的时间为:" + (endTime - startTime));}public static void main(String[] args) {long size = 3000000;String str = "123456";// StringBuilder快但线程不安全:没有加锁synchronizedtest1(size, str); // StringBuffer时间:约125mstest2(size, str); // StringBuilder时间:约73ms}
}
4.2 多线程安全性测试
StringBuffer线程安全测试:
public class Test {public static void main(String[] args) {CountDownLatch cd = new CountDownLatch(1000);StringBuffer sb = new StringBuffer();for(int i = 0; i < 1000; i++) {new StringBufferThread(cd, sb).start();}try {cd.await();System.out.println("长度为:" + sb.length()); // 总是1000} catch (InterruptedException e) {e.printStackTrace();}}
}class StringBufferThread extends Thread {CountDownLatch cd;StringBuffer sb;public StringBufferThread(CountDownLatch cd, StringBuffer sb) {this.cd = cd;this.sb = sb;}public void run() {sb.append("1");cd.countDown();}
}
StringBuilder线程不安全测试:
public class Test {public static void main(String[] args) {CountDownLatch cd = new CountDownLatch(10000);StringBuilder sb = new StringBuilder();for(int i = 0; i < 10000; i++) {new StringBuilderThread(cd, sb).start();}try {cd.await();System.out.println("长度为:" + sb.length()); // 不安全,不总是10000} catch (InterruptedException e) {e.printStackTrace();}}
}class StringBuilderThread extends Thread {CountDownLatch cd;StringBuilder sb;public StringBuilderThread(CountDownLatch cd, StringBuilder sb) {this.cd = cd;this.sb = sb;}public void run() {sb.append("1");cd.countDown();}
}
5. 字符串去重问题
package com.demo1;import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;public class Test2 {public static void main(String[] args) {String str = "a,b,c,a,b,d";System.out.println("半包含: " + str.contains("a"));// String分割后去重(半包含)String[] strArray = str.split(",");Set<String> stringSet = new HashSet<>();for (String s : strArray) {stringSet.add(s);}System.out.println("String去重结果: " + stringSet);System.out.println("----------------------------");// List全包含去重List<String> list = new ArrayList<>();for (String s : strArray) {if (!list.contains(s)) {list.add(s);}}System.out.println("List去重结果: " + list); List<String> list1 = new ArrayList<>();list1.add("abc");System.out.println("全包含: " + list1.contains("a")); }
}
运行结果: