Tại sao có StringBuilder khi có String?


82

Tôi mới gặp StringBuilderlần đầu tiên và rất ngạc nhiên vì Java đã có một Stringlớp rất mạnh cho phép gắn thêm.

Tại sao lại là Stringlớp thứ hai ?

Tôi có thể tìm hiểu về thêm ở đâu StringBuilder?



Tôi chỉ muốn lưu ý rằng điều này thực sự xuất hiện như một câu hỏi phỏng vấn cho tôi một lần. Họ hỏi tôi sẽ điền gì vào một Chuỗi lớn .....
preOtep

Câu trả lời:


171

Stringkhông cho phép bổ sung. Mỗi phương thức bạn gọi trên a Stringsẽ tạo ra một đối tượng mới và trả về nó. Điều này là bởi vì Stringnó là bất biến - nó không thể thay đổi trạng thái bên trong của nó.

Mặt khác StringBuilderlà có thể thay đổi. Khi bạn gọi append(..)nó sẽ thay đổi mảng ký tự bên trong, thay vì tạo một đối tượng chuỗi mới.

Do đó, sẽ hiệu quả hơn nếu có:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 500; i ++) {
    sb.append(i);
}

hơn là str += itạo 500 đối tượng chuỗi mới.

Lưu ý rằng trong ví dụ tôi sử dụng một vòng lặp. Khi helios ghi chú trong các nhận xét, trình biên dịch sẽ tự động dịch các biểu thức String d = a + b + cnhư

String d = new StringBuilder(a).append(b).append(c).toString();

Cũng lưu ý rằng có StringBufferthêm vào StringBuilder. Sự khác biệt là trước đây có các phương thức đồng bộ hóa. Nếu bạn sử dụng nó như một biến cục bộ, hãy sử dụng StringBuilder. Nếu nó xảy ra rằng nó có thể được truy cập bởi nhiều chủ đề, hãy sử dụng StringBuffer(hiếm hơn)


24
+1. Bạn có thể thêm: "do đó StrungBuilder tìm kiếm hiệu suất" và "Trình biên dịch Java thay thế các biểu thức như A + B + C bằng StringBuilder mới (A) .append (B) .append (C) .toString () để tránh hiệu suất tạo đối tượng hình phạt ":)
helios

và tất cả Cảm ơn bạn rất nhiều. Tất cả các bạn đều xứng đáng được +1 (sẽ được gửi nhanh chóng :)
an00b Ngày

siêu giống như việc thu hồi các đối tượng 'bất biến'.
Gary Tsui

Phản hồi tuyệt vời. Tuy nhiên, điều tôi bỏ lỡ là lý do tại sao chúng ta không thể chỉ cho trình biên dịch tìm ra thời điểm chỉ sử dụng Stringbuilder hầu hết thời gian , bao gồm cả trong vòng lặp for, để bạn không cần phải suy nghĩ về nó với tư cách là một nhà phát triển. :)
worldayshi

Câu trả lời tốt . Tôi muốn thêm những dòng này: Chuỗi là bất biến vì mảng (tức là giá trị char []) chứa chuỗi được khai báo là cuối cùng nhưng trong trường hợp StringBuilder thì mảng (tức là giá trị char []) chứa chuỗi không phải là cuối cùng. Bạn có thể thực hiện thay đổi trong mảng nắm giữ chuỗi trong trường hợp của StringBuilder
Deen John

60

Đây là một ví dụ cụ thể về lý do tại sao -

int total = 50000;
String s = ""; 
for (int i = 0; i < total; i++) { s += String.valueOf(i); } 
// 4828ms

StringBuilder sb = new StringBuilder(); 
for (int i = 0; i < total; i++) { sb.append(String.valueOf(i)); } 
// 4ms

Như bạn có thể thấy sự khác biệt về hiệu suất là đáng kể.


Ps. Tôi đã chạy điều này trên Macbook Pro Dual core của mình.
Amir Raminfar

Điều này không giải thích lý do tại sao
Steve Kuo

25
Điều này giải thích tại sao StringBuilder khi có String? Điều này không giải thích tại sao StringBuilder lại nhanh như vậy. nhưng đó không phải là Câu hỏi. Vì vậy, đây là một câu trả lời hợp lệ.
Kerem Baydoğan

2
@krmby - Đồng ý. Để trả lời tại sao thực sự có ý nghĩa cho một câu hỏi khác.
Amir Raminfar

12
Tôi nghĩ để làm cho việc so sánh công bằng, bạn nên tính cả thời gian để thực hiện một s = sb.ToString();ở cuối để ít nhất bạn đã làm như vậy trong cả hai ví dụ (kết quả là a string).
Scott Whitlock

19

Lớp String là bất biến trong khi StringBuilder có thể thay đổi.

String s = "Hello";
s = s + "World";

Đoạn mã trên sẽ tạo ra hai đối tượng vì Chuỗi là bất biến

StringBuilder sb = new StringBuilder("Hello");
sb.append("World");

Đoạn mã trên sẽ chỉ tạo một đối tượng vì StringBuilder không phải là bất biến.

Bài học: Bất cứ khi nào có nhu cầu thao tác / cập nhật / nối thêm String nhiều lần, hãy sử dụng StringBuilder vì nó hiệu quả hơn so với String.


8

StringBuilder dùng để xây dựng các chuỗi. Cụ thể là xây dựng chúng theo một cách rất hiệu quả. Lớp String tốt cho nhiều thứ, nhưng nó thực sự có hiệu suất thực sự khủng khiếp khi lắp ráp một chuỗi mới từ các phần chuỗi nhỏ hơn vì mỗi chuỗi mới là một chuỗi hoàn toàn mới, được phân bổ lại. (Nó không thay đổi ) StringBuilder giữ nguyên trình tự giống nhau và sửa đổi nó ( có thể thay đổi ).


5

Lớp StringBuilder có thể thay đổi và không giống như String, nó cho phép bạn sửa đổi nội dung của chuỗi mà không cần tạo thêm đối tượng String, đây có thể là một lợi ích về hiệu suất khi bạn sửa đổi nhiều một chuỗi. Ngoài ra còn có một bản sao cho StringBuilder được gọi là StringBuffer cũng được đồng bộ hóa nên nó rất lý tưởng cho các môi trường đa luồng.

Vấn đề lớn nhất với String là bất kỳ thao tác nào bạn thực hiện với nó, sẽ luôn trả về một đối tượng mới, chẳng hạn như:

String s1 = "something";
String s2 = "else";
String s3 = s1 + s2; // this is creating a new object.

4

StringBuilder rất tốt khi bạn xử lý các chuỗi lớn hơn. Nó giúp bạn cải thiện hiệu suất.

Đây là một bài báo mà tôi thấy rằng hữu ích.

Một tìm kiếm nhanh trên google có thể đã giúp bạn. Bây giờ bạn đã thuê 7 người khác nhau để thực hiện tìm kiếm trên google cho bạn. :)


Không phải tất cả chúng ta đang làm những công việc không được trả lương ở đây sao?
Deadpool

4

Nói chính xác, StringBuilder thêm tất cả các chuỗi là O (N) trong khi thêm String là O (N ^ 2). Kiểm tra mã nguồn, điều này đạt được nội bộ bằng cách giữ một mảng ký tự có thể thay đổi. StringBuilder sử dụng kỹ thuật nhân đôi độ dài mảng để đạt được hiệu suất O (N ^ 2) được khấu hao , với chi phí có khả năng tăng gấp đôi bộ nhớ cần thiết. Bạn có thể gọi trimToSize ở cuối để giải quyết điều này, nhưng thường các đối tượng StringBuilder chỉ được sử dụng tạm thời. Bạn có thể cải thiện hơn nữa hiệu suất bằng cách cung cấp một dự đoán bắt đầu tốt ở kích thước chuỗi cuối cùng.


3

Hiệu quả.

Mỗi khi bạn nối các chuỗi, một chuỗi mới sẽ được tạo. Ví dụ:

String out = "a" + "b" + "c";

Điều này tạo ra một chuỗi mới, tạm thời, sao chép "a" và "b" vào nó để dẫn đến "ab". Sau đó, nó tạo một chuỗi mới tạm thời khác, sao chép "ab" và "c" vào đó, để dẫn đến "abc". Kết quả này sau đó được gán choout .

Kết quả là thuật toán của Schlemiel the Painter độ phức tạp thời gian O (n²) (bậc hai).

StringBuilder, mặt khác, cho phép bạn nối các chuỗi tại chỗ, thay đổi kích thước chuỗi đầu ra nếu cần.


Nhiều triển khai JVM sẽ biên dịch ví dụ của bạn thành một StringBuilder và sau đó chuyển đổi kết quả cuối cùng thành Chuỗi. Trong trường hợp như vậy, nó sẽ không được tập hợp bằng cách phân bổ Chuỗi lặp lại.
scottb 21/09/13

1

Java có String, StringBuffer và StringBuilder:

  • Chuỗi: Bất biến của nó

  • StringBuffer: Có thể thay đổi và ThreadSafe của nó

  • StringBuilder: Có thể thay đổi nhưng không phải ThreadSafe, được giới thiệu trong Java 1.5

Chuỗi ví dụ:

public class T1 {

    public static void main(String[] args){

        String s = "Hello";

        for (int i=0;i<10;i++) {

            s = s+"a";
            System.out.println(s);
        }
    }
}

}

đầu ra: 10 Chuỗi khác nhau sẽ được tạo thay vì chỉ 1 Chuỗi.

Helloa
Helloaa
Helloaaa
Helloaaaa
Helloaaaaa
Helloaaaaaa
Helloaaaaaaa
Helloaaaaaaaa 
Helloaaaaaaaaa 
Helloaaaaaaaaaa

Ví dụ: StringBuilder: Chỉ 1 đối tượng StringBuilder sẽ được tạo.

public class T1 {

    public static void main(String[] args){

        StringBuilder s = new StringBuilder("Hello");

        for (int i=0;i<10;i++) {    
            s.append("a");
            System.out.println(s);
        }
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.