首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 字串反轉五種實作方式效能對比

     編輯:Java 相關知識

Java 字串反轉完整實作指南與效能分析

字串反轉是經典面試題,也是實務中常見操作 (如回文判斷、加密演算法、資料轉換)。本文介紹五種主流實作方式,從簡單易懂到高效能生產級,並提供 JMH 基準測試框架讓你在專案中實測選型。

五種實作方式

1. StringBuilder.reverse() - 生產首選


public static String reverseStringBuilder(String str) {
    if (str == null) return null;
    return new StringBuilder(str).reverse().toString();
}
  • JDK 內建、高度優化、原生碼實作 (JDK 9+ 使用 StringLatin1.reverse/StringUTF16.reverse)
  • 線程安全 (非共享)、可變緩衝區、單次分配
  • 推薦等級:⭐⭐⭐⭐⭐

2. 字元陣列雙指針交換 - 手寫高效能


public static String reverseCharArray(String str) {
    if (str == null) return null;
    char[] arr = str.toCharArray();
    int left = 0, right = arr.length - 1;
    while (left < right) {
        char tmp = arr[left];
        arr[left] = arr[right];
        arr[right] = tmp;
        left++; right--;
    }
    return new String(arr);
}
  • 原地交換、零額外物件 (除輸出字串)、緩存友好
  • 適合嵌入式/極致效能場景、教學展示演算法
  • 推薦等級:⭐⭐⭐⭐

3. 遞歸 + substring - 教學用、效能差


public static String reverseRecursive(String str) {
    if (str == null || str.length() <= 1) return str;
    return str.charAt(str.length() - 1) + reverseRecursive(str.substring(0, str.length() - 1));
}
  • 每層遞歸建立新字串、substring 複製陣列 (JDK 7+)、O(n²) 時間、O(n) 棧深度
  • 長字串導致 StackOverflowError、大量 GC 壓力
  • 推薦等級:⭐ (僅教學)

4. Stream API - 函數式風格


public static String reverseStream(String str) {
    if (str == null) return null;
    return str.chars()
        .mapToObj(c -> (char) c)
        .reduce("", (acc, c) -> c + acc, (a, b) -> b + a); // 字串拼接極慢
}

// 改進版:收集到陣列再反轉
public static String reverseStreamImproved(String str) {
    if (str == null) return null;
    return str.chars()
        .mapToObj(c -> (char) c)
        .collect(StringBuilder::new, (sb, c) -> sb.append(c), StringBuilder::append)
        .reverse()
        .toString();
}
  • 函數式表達、並行潛力 (但反轉無並行增益)
  • 原版字串拼接 O(n²),改進版接近 StringBuilder
  • 推薦等級:⭐⭐⭐

5. ByteBuffer / 位元組層面 - 特殊編碼場景


public static String reverseBytes(String str, Charset charset) {
    if (str == null) return null;
    byte[] bytes = str.getBytes(charset);
    ByteBuffer buf = ByteBuffer.wrap(bytes);
    byte[] reversed = new byte[bytes.length];
    for (int i = bytes.length - 1; i >= 0; i--) {
        reversed[bytes.length - 1 - i] = bytes[i];
    }
    return new String(reversed, charset);
}
  • 處理特定編碼位元組序列反轉 (非字元反轉)
  • 多位元組字元 (UTF-8 中文) 會產生無效位元組序列,**慎用**
  • 推薦等級:⭐ (特殊需求)

JMH 基準測試框架


import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Benchmark)
@Warmup(iterations = 3, time = 1)
@Measurement(iterations = 5, time = 1)
@Fork(1)
public class StringReverseBenchmark {
    
    @Param({"10", "100", "1000", "10000"})
    public int length;
    
    private String testString;
    
    @Setup
    public void setup() {
        // 生成隨機字串
        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            sb.append((char) ('a' + (i % 26)));
        }
        testString = sb.toString();
    }
    
    @Benchmark
    public String stringBuilder() {
        return new StringBuilder(testString).reverse().toString();
    }
    
    @Benchmark
    public String charArray() {
        char[] arr = testString.toCharArray();
        int l = 0, r = arr.length - 1;
        while (l < r) { char t = arr[l]; arr[l] = arr[r]; arr[r] = t; l++; r--; }
        return new String(arr);
    }
    
    @Benchmark
    public String streamImproved() {
        return testString.chars()
            .mapToObj(c -> (char) c)
            .collect(StringBuilder::new, (sb, c) -> sb.append(c), StringBuilder::append)
            .reverse().toString();
    }
}

典型測試結果參考 (JDK 17, x86_64)

字串長度StringBuilder (ns)CharArray (ns)Stream Improved (ns)遞歸 (ns)
10~80~60~200~5000
100~300~250~1200~500000 (OOM 風險)
1000~2500~2200~11000StackOverflow
10000~22000~20000~110000N/A

特殊情況處理

場景處理方式
Unicode 補充字元 (Emoji、罕用字)用 codePoints() 處理 code point 而非 char:
str.codePoints().toArray() → 反轉 int[] → new String(cp, 0, cp.length)
不可變字串常量池反轉後為新物件,不影響原字串
null/空字串開頭防御性檢查 if (str == null || str.isEmpty()) return str;
極大字串 (>100MB)分塊處理、記憶體映射、或外部排序算法,避免雙倍記憶體

總結建議

  1. 生產代碼:new StringBuilder(str).reverse().toString() - 簡潔、高效、JDK 保證
  2. 效能極致/教學:字元陣列雙指針 - 可控、零額外分配、展示演算法
  3. 函數式風格:Stream + StringBuilder 收集器 - 團隊風格統一時
  4. 避免:遞歸、字串拼接 (+)、ByteBuffer 字元反轉
  5. Unicode 安全:含 Emoji 時必須用 code point 級別反轉
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved