java字符串处理全解析:string、stringbuilder与stringbuffer
一、string类基础
1. string的本质
- 不可变对象:java中的string对象一旦创建就不能修改
- 底层实现:基于
private final char value[]字符数组 - 字符串池:jvm维护的特殊存储区域,用于存储字符串字面量
2. 创建string对象的两种方式
// 方式1:字面量创建(直接存入字符串池)
string s1 = "hello";
// 方式2:new创建(堆内存新建对象)
string s2 = new string("hello");3. 字符串比较
string a = "java";
string b = "java";
string c = new string("java");
system.out.println(a == b); // true(指向字符串池同一对象)
system.out.println(a == c); // false(不同对象)
system.out.println(a.equals(c)); // true(内容相同)4. 常用方法
| 方法 | 说明 | 示例 |
|---|---|---|
length() | 获取长度 | "abc".length() → 3 |
charat() | 获取指定位置字符 | "abc".charat(1) → ‘b’ |
substring() | 截取子串 | "hello".substring(1,3) → “el” |
indexof() | 查找字符位置 | "java".indexof('a') → 1 |
tolowercase() | 转小写 | "java".tolowercase() → “java” |
touppercase() | 转大写 | "java".touppercase() → “java” |
trim() | 去除首尾空格 | " java ".trim() → “java” |
split() | 分割字符串 | "a,b,c".split(",") → [“a”,“b”,“c”] |
replace() | 替换字符 | "java".replace('a','o') → “jovo” |
二、stringbuilder与stringbuffer
1. 可变字符串类比较
| 特性 | string | stringbuilder | stringbuffer |
|---|---|---|---|
| 可变性 | 不可变 | 可变 | 可变 |
| 线程安全 | 是 | 否 | 是 |
| 性能 | 低 | 高 | 中等 |
| 使用场景 | 少量操作 | 单线程大量操作 | 多线程大量操作 |
2. stringbuilder核心方法
stringbuilder sb = new stringbuilder();
// 链式调用
sb.append("java").append(" is").append(" awesome!");
system.out.println(sb); // "java is awesome!"
sb.insert(5, "really "); // 插入
sb.delete(5, 12); // 删除
sb.replace(0, 4, "kotlin"); // 替换
sb.reverse(); // 反转3. stringbuffer线程安全示例
class bufferthread extends thread {
private stringbuffer buffer;
public bufferthread(stringbuffer buffer) {
this.buffer = buffer;
}
@override
public void run() {
for(int i=0; i<100; i++){
buffer.append(i);
}
}
}
public class threadsafedemo {
public static void main(string[] args) throws interruptedexception {
stringbuffer buffer = new stringbuffer();
thread t1 = new bufferthread(buffer);
thread t2 = new bufferthread(buffer);
t1.start();
t2.start();
t1.join();
t2.join();
system.out.println("最终长度: " + buffer.length()); // 正确输出200
}
}三、性能对比实验
1. 字符串拼接测试
public class performancetest {
static final int loop_count = 100000;
public static void stringtest() {
long start = system.currenttimemillis();
string s = "";
for(int i=0; i<loop_count; i++){
s += "a";
}
system.out.println("string耗时: " + (system.currenttimemillis()-start) + "ms");
}
public static void buildertest() {
long start = system.currenttimemillis();
stringbuilder sb = new stringbuilder();
for(int i=0; i<loop_count; i++){
sb.append("a");
}
system.out.println("stringbuilder耗时: " + (system.currenttimemillis()-start) + "ms");
}
public static void buffertest() {
long start = system.currenttimemillis();
stringbuffer sb = new stringbuffer();
for(int i=0; i<loop_count; i++){
sb.append("a");
}
system.out.println("stringbuffer耗时: " + (system.currenttimemillis()-start) + "ms");
}
public static void main(string[] args) {
stringtest(); // 约4500ms
buildertest(); // 约5ms
buffertest(); // 约10ms
}
}2. 内存占用分析
// 使用jvisualvm观察内存变化
public class memorydemo {
public static void main(string[] args) throws interruptedexception {
system.out.println("开始测试...");
thread.sleep(10000); // 等待连接visualvm
// string会产生大量中间对象
string s = "";
for(int i=0; i<100000; i++){
s += i;
}
// stringbuilder只创建一个对象
stringbuilder sb = new stringbuilder();
for(int i=0; i<100000; i++){
sb.append(i);
}
thread.sleep(10000); // 观察内存变化
}
}四、字符串最佳实践
1. 选择策略
- string:少量操作、字符串常量、作为方法参数
- stringbuilder:单线程环境下大量字符串操作
- stringbuffer:多线程环境下大量字符串操作
2. 优化技巧
// 不好的写法
string result = "";
for(string str : stringlist) {
result += str; // 每次循环创建新string对象
}
// 好的写法
stringbuilder builder = new stringbuilder();
for(string str : stringlist) {
builder.append(str);
}
string result = builder.tostring();3. 字符串常量池优化
// 推荐写法(利用字符串池)
string s1 = "hello";
string s2 = "hello"; // 复用s1对象
// 不推荐写法(创建多余对象)
string s3 = new string("hello"); // 强制创建新对象五、扩展知识
1. 字符串压缩(java 9+)
java 9后string底层改用byte[]存储,并添加了编码标志字段:
// 查看字符串编码方式
string str = "你好java";
field field = string.class.getdeclaredfield("coder");
field.setaccessible(true);
byte coder = (byte) field.get(str);
system.out.println(coder); // 0表示latin-1,1表示utf-162. 字符串拼接底层优化
// java编译器会自动优化为stringbuilder
string s = "a" + "b" + "c";
// 编译后等价于:
string s = new stringbuilder().append("a").append("b").append("c").tostring();3. 正则表达式应用
// 验证邮箱格式
string email = "test@example.com";
string regex = "^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$";
boolean isvalid = email.matches(regex);
// 提取数字
string text = "订单123金额456";
pattern pattern = pattern.compile("\\d+");
matcher matcher = pattern.matcher(text);
while(matcher.find()) {
system.out.println("找到数字: " + matcher.group());
}4. 字符串格式化
// 传统方式
string info1 = string.format("姓名: %s, 年龄: %d", "张三", 25);
// java 15+文本块
string json = """
{
"name": "%s",
"age": %d
}
""".formatted("李四", 30);六、高级应用案例
1. 实现一个简单的模板引擎
public class templateengine {
private final string template;
public templateengine(string template) {
this.template = template;
}
public string render(map<string, object> params) {
stringbuilder result = new stringbuilder(template);
for(map.entry<string, object> entry : params.entryset()) {
string key = "${" + entry.getkey() + "}";
string value = entry.getvalue().tostring();
int index;
while((index = result.indexof(key)) != -1) {
result.replace(index, index + key.length(), value);
}
}
return result.tostring();
}
public static void main(string[] args) {
string template = "欢迎您,${user}!今天是${day}。";
map<string, object> params = new hashmap<>();
params.put("user", "王五");
params.put("day", "2023-05-20");
templateengine engine = new templateengine(template);
system.out.println(engine.render(params));
}
}2. 字符串相似度比较
public class stringsimilarity {
// 计算levenshtein距离
public static int levenshteindistance(string a, string b) {
int[][] dp = new int[a.length()+1][b.length()+1];
for(int i=0; i<=a.length(); i++) dp[i][0] = i;
for(int j=0; j<=b.length(); j++) dp[0][j] = j;
for(int i=1; i<=a.length(); i++) {
for(int j=1; j<=b.length(); j++) {
int cost = (a.charat(i-1) == b.charat(j-1)) ? 0 : 1;
dp[i][j] = math.min(
math.min(dp[i-1][j]+1, dp[i][j-1]+1),
dp[i-1][j-1]+cost
);
}
}
return dp[a.length()][b.length()];
}
// 计算相似度百分比
public static double similarity(string a, string b) {
int maxlen = math.max(a.length(), b.length());
if(maxlen == 0) return 1.0;
return (1 - (double)levenshteindistance(a,b)/maxlen) * 100;
}
public static void main(string[] args) {
string s1 = "kitten";
string s2 = "sitting";
system.out.printf("相似度: %.2f%%", similarity(s1, s2));
}
}七、常见面试题解析
1. string为什么设计为不可变?
- 安全性:作为参数传递时不会被意外修改
- 线程安全:无需同步即可在多线程中使用
- 缓存哈希:string常用作hashmap的key,hashcode可缓存
- 字符串池:实现字符串常量池的基础
2. string s = new string(“xyz”)创建了几个对象?
- 如果"xyz"不在字符串池中:2个(字符串池中1个,堆中1个)
- 如果"xyz"已在字符串池中:1个(只在堆中创建新对象)
3. 如何高效拼接字符串数组?
// 使用stringjoiner(java 8+)
stringjoiner sj = new stringjoiner(", ", "[", "]");
for(string str : array) {
sj.add(str);
}
string result = sj.tostring();
// 或者直接使用string.join()
string result = string.join(", ", array);4. 如何实现字符串反转?
// 方法1:使用stringbuilder
new stringbuilder(str).reverse().tostring();
// 方法2:字符数组交换
char[] chars = str.tochararray();
for(int i=0, j=chars.length-1; i<j; i++,j--) {
char temp = chars[i];
chars[i] = chars[j];
chars[j] = temp;
}
new string(chars);八、总结与最佳实践
1. 关键点回顾
- string是不可变对象,适合少量操作和作为常量
- stringbuilder是可变、非线程安全的字符串操作类
- stringbuffer是线程安全版本的stringbuilder
- 大量字符串操作时应避免直接使用string
2. 性能优化建议
- 预分配stringbuilder容量:
new stringbuilder(initialcapacity) - 避免在循环中使用
+拼接字符串 - 使用
string.join()替代手动拼接分隔字符串 - 考虑使用
charsequence接口作为方法参数类型
通过深入理解java字符串处理机制,开发者可以编写出更高效、更健壮的字符串处理代码,这对日常开发中的文本处理、数据格式化和系统间通信等场景至关重要。
到此这篇关于java字符串处理的文章就介绍到这了,更多相关java字符串处理内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论