Java字符串處理全解析(String、StringBuilder與StringBuffer)
Java字符串處理全解析:String、StringBuilder與StringBuffer
一、String類基礎(chǔ)
1. String的本質(zhì)
- 不可變對(duì)象:Java中的String對(duì)象一旦創(chuàng)建就不能修改
- 底層實(shí)現(xiàn):基于
private final char value[]字符數(shù)組 - 字符串池:JVM維護(hù)的特殊存儲(chǔ)區(qū)域,用于存儲(chǔ)字符串字面量
2. 創(chuàng)建String對(duì)象的兩種方式
// 方式1:字面量創(chuàng)建(直接存入字符串池)
String s1 = "Hello";
// 方式2:new創(chuàng)建(堆內(nèi)存新建對(duì)象)
String s2 = new String("Hello");3. 字符串比較
String a = "Java";
String b = "Java";
String c = new String("Java");
System.out.println(a == b); // true(指向字符串池同一對(duì)象)
System.out.println(a == c); // false(不同對(duì)象)
System.out.println(a.equals(c)); // true(內(nèi)容相同)4. 常用方法
| 方法 | 說明 | 示例 |
|---|---|---|
length() | 獲取長度 | "abc".length() → 3 |
charAt() | 獲取指定位置字符 | "abc".charAt(1) → ‘b’ |
substring() | 截取子串 | "Hello".substring(1,3) → “el” |
indexOf() | 查找字符位置 | "Java".indexOf('a') → 1 |
toLowerCase() | 轉(zhuǎn)小寫 | "Java".toLowerCase() → “java” |
toUpperCase() | 轉(zhuǎn)大寫 | "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();
// 鏈?zhǔn)秸{(diào)用
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(); // 反轉(zhuǎn)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
}
}三、性能對(duì)比實(shí)驗(yàn)
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耗時(shí): " + (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耗時(shí): " + (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耗時(shí): " + (System.currentTimeMillis()-start) + "ms");
}
public static void main(String[] args) {
stringTest(); // 約4500ms
builderTest(); // 約5ms
bufferTest(); // 約10ms
}
}2. 內(nèi)存占用分析
// 使用jvisualvm觀察內(nèi)存變化
public class MemoryDemo {
public static void main(String[] args) throws InterruptedException {
System.out.println("開始測試...");
Thread.sleep(10000); // 等待連接VisualVM
// String會(huì)產(chǎn)生大量中間對(duì)象
String s = "";
for(int i=0; i<100000; i++){
s += i;
}
// StringBuilder只創(chuàng)建一個(gè)對(duì)象
StringBuilder sb = new StringBuilder();
for(int i=0; i<100000; i++){
sb.append(i);
}
Thread.sleep(10000); // 觀察內(nèi)存變化
}
}四、字符串最佳實(shí)踐
1. 選擇策略
- String:少量操作、字符串常量、作為方法參數(shù)
- StringBuilder:單線程環(huán)境下大量字符串操作
- StringBuffer:多線程環(huán)境下大量字符串操作
2. 優(yōu)化技巧
// 不好的寫法
String result = "";
for(String str : stringList) {
result += str; // 每次循環(huán)創(chuàng)建新String對(duì)象
}
// 好的寫法
StringBuilder builder = new StringBuilder();
for(String str : stringList) {
builder.append(str);
}
String result = builder.toString();3. 字符串常量池優(yōu)化
// 推薦寫法(利用字符串池)
String s1 = "Hello";
String s2 = "Hello"; // 復(fù)用s1對(duì)象
// 不推薦寫法(創(chuàng)建多余對(duì)象)
String s3 = new String("Hello"); // 強(qiáng)制創(chuàng)建新對(duì)象五、擴(kuò)展知識(shí)
1. 字符串壓縮(Java 9+)
Java 9后String底層改用byte[]存儲(chǔ),并添加了編碼標(biāo)志字段:
// 查看字符串編碼方式
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. 字符串拼接底層優(yōu)化
// Java編譯器會(huì)自動(dòng)優(yōu)化為StringBuilder
String s = "a" + "b" + "c";
// 編譯后等價(jià)于:
String s = new StringBuilder().append("a").append("b").append("c").toString();3. 正則表達(dá)式應(yīng)用
// 驗(yàn)證郵箱格式
String email = "test@example.com";
String regex = "^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$";
boolean isValid = email.matches(regex);
// 提取數(shù)字
String text = "訂單123金額456";
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher(text);
while(matcher.find()) {
System.out.println("找到數(shù)字: " + matcher.group());
}4. 字符串格式化
// 傳統(tǒng)方式
String info1 = String.format("姓名: %s, 年齡: %d", "張三", 25);
// Java 15+文本塊
String json = """
{
"name": "%s",
"age": %d
}
""".formatted("李四", 30);六、高級(jí)應(yīng)用案例
1. 實(shí)現(xiàn)一個(gè)簡單的模板引擎
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 {
// 計(jì)算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()];
}
// 計(jì)算相似度百分比
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為什么設(shè)計(jì)為不可變?
- 安全性:作為參數(shù)傳遞時(shí)不會(huì)被意外修改
- 線程安全:無需同步即可在多線程中使用
- 緩存哈希:String常用作HashMap的key,hashCode可緩存
- 字符串池:實(shí)現(xiàn)字符串常量池的基礎(chǔ)
2. String s = new String(“xyz”)創(chuàng)建了幾個(gè)對(duì)象?
- 如果"xyz"不在字符串池中:2個(gè)(字符串池中1個(gè),堆中1個(gè))
- 如果"xyz"已在字符串池中:1個(gè)(只在堆中創(chuàng)建新對(duì)象)
3. 如何高效拼接字符串?dāng)?shù)組?
// 使用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. 如何實(shí)現(xiàn)字符串反轉(zhuǎn)?
// 方法1:使用StringBuilder
new StringBuilder(str).reverse().toString();
// 方法2:字符數(shù)組交換
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);八、總結(jié)與最佳實(shí)踐
1. 關(guān)鍵點(diǎn)回顧
- String是不可變對(duì)象,適合少量操作和作為常量
- StringBuilder是可變、非線程安全的字符串操作類
- StringBuffer是線程安全版本的StringBuilder
- 大量字符串操作時(shí)應(yīng)避免直接使用String
2. 性能優(yōu)化建議
- 預(yù)分配StringBuilder容量:
new StringBuilder(initialCapacity) - 避免在循環(huán)中使用
+拼接字符串 - 使用
String.join()替代手動(dòng)拼接分隔字符串 - 考慮使用
CharSequence接口作為方法參數(shù)類型
通過深入理解Java字符串處理機(jī)制,開發(fā)者可以編寫出更高效、更健壯的字符串處理代碼,這對(duì)日常開發(fā)中的文本處理、數(shù)據(jù)格式化和系統(tǒng)間通信等場景至關(guān)重要。
到此這篇關(guān)于Java字符串處理的文章就介紹到這了,更多相關(guān)Java字符串處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 辨析Java中的String與StringBuffer及StringBuilder字符串類
- Java中String、StringBuffer和StringBuilder的區(qū)別與使用場景
- Java中String、StringBuffer和StringBuilder的區(qū)別
- Java中的String、StringBuilder、StringBuffer三者的區(qū)別詳解
- java String、StringBuilder和StringBuffer的區(qū)別詳解
- java 中String和StringBuffer與StringBuilder的區(qū)別及使用方法
- Java 中String StringBuilder 與 StringBuffer詳解及用法實(shí)例
- 全面解釋java中StringBuilder、StringBuffer、String類之間的關(guān)系
相關(guān)文章
淺析Spring Boot單體應(yīng)用熔斷技術(shù)的使用
這篇文章主要介紹了淺析Spring Boot單體應(yīng)用熔斷技術(shù)的使用,幫助大家更好的理解和使用spirngboot框架,感興趣的朋友可以了解下2021-01-01
JavaSE基礎(chǔ)之反射機(jī)制(反射Class)詳解
反射機(jī)制有什么用?通過java語言中的反射機(jī)制可以操作字節(jié)碼文件,可以讀和修改字節(jié)碼文件。所以本文將為大家講講反射機(jī)制的使用,需要的可以參考一下2022-09-09
使用Spring Initializr方式如何快速構(gòu)建Spring Boot項(xiàng)目
Spring lnitializr是一個(gè)Web應(yīng)用,它提供了一個(gè)基本的項(xiàng)目結(jié)構(gòu),能夠幫助我們快速構(gòu)建一個(gè)基礎(chǔ)的Spring Boot項(xiàng)目,本文分步驟講解如何使用Spring Initializr方式構(gòu)建Spring Boot項(xiàng)目,感興趣的朋友跟隨小編一起看看吧2023-08-08
Java 格式化輸出JSON字符串的2種實(shí)現(xiàn)操作
這篇文章主要介紹了Java 格式化輸出JSON字符串的2種實(shí)現(xiàn)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-10-10
IntelliJ IDEA 的 Spring 項(xiàng)目如何查看 @Value 的配置和值(方法詳解)
這篇文章主要介紹了IntelliJ IDEA 的 Spring 項(xiàng)目如何查看 @Value 的配置和值,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10
RabbitMq消息防丟失功能實(shí)現(xiàn)方式講解
這篇文章主要介紹了RabbitMq消息防丟失功能實(shí)現(xiàn),RabbitMQ中,消息丟失可以簡單的分為兩種:客戶端丟失和服務(wù)端丟失。針對(duì)這兩種消息丟失,RabbitMQ都給出了相應(yīng)的解決方案2023-01-01

