2009-06-18 69 views
12

Thực tế là phương thức thay thế trả về một đối tượng chuỗi thay vì thay thế nội dung của một chuỗi đã cho là một chút ngớ ngẩn (nhưng dễ hiểu khi bạn biết rằng các chuỗi không thay đổi trong Java). Tôi đang thực hiện một hit hiệu suất lớn bằng cách sử dụng một thay thế lồng nhau sâu sắc trong một số mã. Có cái gì tôi có thể thay thế nó bằng cách đó sẽ làm cho nó nhanh hơn?Các phương án thay thế nhanh hơn để thay thế phương thức trong một chuỗi Java?

+5

heh heh thay thế – ojblass

+1

Bạn sử dụng chuỗi? bạn điên à? sử dụng mảng byte! – IAdapter

Trả lời

19

Đây là ý nghĩa của số StringBuilder. Nếu bạn định thực hiện rất nhiều thao tác, hãy thực hiện thao tác trên StringBuilder, sau đó biến điều đó thành một String bất cứ khi nào bạn cần.

StringBuilder được mô tả như sau:

"Một chuỗi có thể thay đổi các ký tự Lớp này cung cấp một API tương thích với StringBuffer, nhưng không có bảo lãnh của đồng bộ hóa".

Nó có replace (và append, insert, delete, et al) và bạn có thể sử dụng toString để morph nó thành một thực String.

+0

Cũng nhớ sử dụng StringBuilder nếu bạn không yêu cầu an toàn luồng, thường nhanh hơn và hoạt động tương tự. –

+0

Ngoài ra, StringBuilder.replace hoạt động khá khác so với String.replace, vì vậy bạn không thể sử dụng nó như là một thay thế drop-in! –

0

Tất cả thao tác chuỗi nói chung đều rất chậm. Hãy xem xét để sử dụng StringBuffer, nó không chính xác như lớp String, nhưng có rất nhiều điểm chung và nó cũng có thể thay đổi.

+1

Nói chung, nếu bạn không cần bộ đệm của bạn để được an toàn thread (tức là bạn không có nhiều chủ đề thao tác cùng một bộ đệm cùng một lúc), bạn nên sử dụng StringBuilder thay vì StringBuffer. – Avi

+2

Từ tài liệu StringBuffer: Lớp StringBuilder nói chung nên được sử dụng ưu tiên này, vì nó hỗ trợ tất cả các hoạt động tương tự nhưng nó nhanh hơn, vì nó thực hiện không đồng bộ hóa. – tgamblin

+0

Tôi từng làm việc rất nhiều với môi trường đa luồng nên StringBuffer xuất hiện trong đầu tôi một cách tự nhiên. –

4

Tôi đồng ý với các điều trên. Sử dụng StringBuffer để đảm bảo an toàn cho luồng và StringBuilder khi làm việc với các chuỗi đơn lẻ.

7

Các bài đăng trước đó là đúng, StringBuilder/StringBuffer là một giải pháp.

Nhưng, bạn cũng phải đặt câu hỏi liệu có nên thay thế các dây lớn trong bộ nhớ hay không.

Tôi thường có các thao tác chuỗi được triển khai dưới dạng luồng, do đó thay vì thay thế nó trong chuỗi và sau đó gửi nó đến OutputStream, tôi thay thế tại thời điểm tôi gửi Chuỗi tới đầu ra. Điều đó hoạt động nhanh hơn nhiều so với bất kỳ thay thế nào.

Điều này hoạt động nhanh hơn nhiều nếu bạn muốn thay thế này để triển khai cơ chế mẫu. Phát trực tuyến luôn nhanh hơn vì bạn tiêu thụ ít bộ nhớ hơn và nếu khách hàng chậm, bạn chỉ cần tạo ở tốc độ chậm - vì vậy, quy mô sẽ tốt hơn nhiều.

+2

Bạn có thể cung cấp một ví dụ không? –

1

Nếu bạn có một số chuỗi để thay thế (chẳng hạn như chuỗi thoát XML), đặc biệt khi thay thế có độ dài khác với mẫu, thuật toán kiểu lexer FSM có vẻ như hiệu quả nhất, tương tự như đề xuất xử lý trong một dòng thời trang, nơi đầu ra được xây dựng từng bước.

Có lẽ đối tượng Matcher có thể được sử dụng để thực hiện điều đó một cách hiệu quả.

1

Chỉ cần lấy số char[] của số String và lặp lại qua nó. Sử dụng tạm thời StringBuilder.

Tìm mẫu bạn muốn thay thế trong khi lặp nếu bạn không tìm thấy mẫu, viết nội dung bạn đã quét đến StringBuilder, viết văn bản thay thế khác vào StringBuilder.

2

Thêm vào câu trả lời @paxdiablo, dưới đây là ví dụ về việc triển khai mẫu thay thếTất cả bằng cách sử dụng StringBuffers nhanh hơn 3.7 lần so với Chuỗi.replaceAll():

Code:

public static String replaceAll(final String str, final String searchChars, String replaceChars) 
{ 
    if ("".equals(str) || "".equals(searchChars) || searchChars.equals(replaceChars)) 
    { 
    return str; 
    } 
    if (replaceChars == null) 
    { 
    replaceChars = ""; 
    } 
    final int strLength = str.length(); 
    final int searchCharsLength = searchChars.length(); 
    StringBuilder buf = new StringBuilder(str); 
    boolean modified = false; 
    for (int i = 0; i < strLength; i++) 
    { 
    int start = buf.indexOf(searchChars, i); 

    if (start == -1) 
    { 
     if (i == 0) 
     { 
     return str; 
     } 
     return buf.toString(); 
    } 
    buf = buf.replace(start, start + searchCharsLength, replaceChars); 
    modified = true; 

    } 
    if (!modified) 
    { 
    return str; 
    } 
    else 
    { 
    return buf.toString(); 
    } 
} 

Test Case - đầu ra là như sau (delta1 = 1917009502; Delta2 = 7241000026):

@Test 
public void testReplaceAll() 
{ 
    String origStr = "1234567890-1234567890-"; 

    String replacement1 = StringReplacer.replaceAll(origStr, "0", "a"); 
    String expectedRep1 = "123456789a-123456789a-"; 

    String replacement2 = StringReplacer.replaceAll(origStr, "0", "ab"); 
    String expectedRep2 = "123456789ab-123456789ab-"; 

    String replacement3 = StringReplacer.replaceAll(origStr, "0", ""); 
    String expectedRep3 = "123456789-123456789-"; 


    String replacement4 = StringReplacer.replaceAll(origStr, "012", "a"); 
    String expectedRep4 = "1234567890-1234567890-"; 

    String replacement5 = StringReplacer.replaceAll(origStr, "123", "ab"); 
    String expectedRep5 = "ab4567890-ab4567890-"; 

    String replacement6 = StringReplacer.replaceAll(origStr, "123", "abc"); 
    String expectedRep6 = "abc4567890-abc4567890-"; 

    String replacement7 = StringReplacer.replaceAll(origStr, "123", "abcdd"); 
    String expectedRep7 = "abcdd4567890-abcdd4567890-"; 

    String replacement8 = StringReplacer.replaceAll(origStr, "123", ""); 
    String expectedRep8 = "4567890-4567890-"; 

    String replacement9 = StringReplacer.replaceAll(origStr, "123", ""); 
    String expectedRep9 = "4567890-4567890-"; 

    assertEquals(replacement1, expectedRep1); 
    assertEquals(replacement2, expectedRep2); 
    assertEquals(replacement3, expectedRep3); 
    assertEquals(replacement4, expectedRep4); 
    assertEquals(replacement5, expectedRep5); 
    assertEquals(replacement6, expectedRep6); 
    assertEquals(replacement7, expectedRep7); 
    assertEquals(replacement8, expectedRep8); 
    assertEquals(replacement9, expectedRep9); 

    long start1 = System.nanoTime(); 
    for (long i = 0; i < 10000000L; i++) 
    { 
    String rep = StringReplacer.replaceAll(origStr, "123", "abcdd"); 
    } 
    long delta1 = System.nanoTime() -start1; 

    long start2= System.nanoTime(); 

    for (long i = 0; i < 10000000L; i++) 
    { 
    String rep = origStr.replaceAll("123", "abcdd"); 
    } 

    long delta2 = System.nanoTime() -start1; 

    assertTrue(delta1 < delta2); 

    System.out.printf("Delta1 = %d; Delta2 =%d", delta1, delta2); 


} 
0

Khi bạn đang thay thế ký tự đơn , hãy xem xét việc lặp qua mảng ký tự của bạn nhưng thay thế các ký tự bằng cách sử dụng (được tạo trước) HashMap<Character, Character>().

Tôi sử dụng chiến lược này để chuyển đổi chuỗi số mũ số nguyên theo ký tự siêu âm unicode.

Tốc độ nhanh gấp hai lần so với String.replace(char, char). Lưu ý rằng thời gian liên quan đến việc tạo bản đồ băm không được bao gồm trong so sánh này.

3

Mã sau là xấp xỉ. Nhanh hơn 30 lần nếu không có trận đấu và nhanh gấp 5 lần nếu có trận đấu.

static String fastReplace(String str, String target, String replacement) { 
    int targetLength = target.length(); 
    if(targetLength == 0) { 
     return str; 
    } 
    int idx2 = str.indexOf(target); 
    if(idx2 < 0) { 
     return str; 
    } 
    StringBuilder buffer = new StringBuilder(targetLength > replacement.length() ? str.length() : str.length() * 2); 
    int idx1 = 0; 
    do { 
     buffer.append(str, idx1, idx2); 
     buffer.append(replacement); 
     idx1 = idx2 + targetLength; 
     idx2 = str.indexOf(target, idx1); 
    } while(idx2 > 0); 
    buffer.append(str, idx1, str.length()); 
    return buffer.toString(); 
} 
Các vấn đề liên quan