2012-01-06 6 views
23

Đối với nối chuỗi chúng ta có thể sử dụng concat() hoặc toán tử concat (+).Toán tử ghép nối (+) so với concat()

Tôi đã thử kiểm tra hiệu suất sau và tìm thấy concat() là cách nhanh hơn và hiệu quả về bộ nhớ để nối chuỗi.

String nối so với 100.000 lần:

String str = null; 

//------------Using Concatenation operator------------- 
long time1 = System.currentTimeMillis(); 
long freeMemory1 = Runtime.getRuntime().freeMemory(); 

for(int i=0; i<100000; i++){ 
    str = "Hi"; 
    str = str+" Bye"; 
} 
long time2 = System.currentTimeMillis(); 
long freeMemory2 = Runtime.getRuntime().freeMemory(); 

long timetaken1 = time2-time1; 
long memoryTaken1 = freeMemory1 - freeMemory2; 
System.out.println("Concat operator :" + "Time taken =" + timetaken1 + 
        " Memory Consumed =" + memoryTaken1); 

//------------Using Concat method------------- 
long time3 = System.currentTimeMillis(); 
long freeMemory3 = Runtime.getRuntime().freeMemory(); 
for(int j=0; j<100000; j++){ 
    str = "Hi"; 
    str = str.concat(" Bye"); 
} 
long time4 = System.currentTimeMillis(); 
long freeMemory4 = Runtime.getRuntime().freeMemory(); 
long timetaken2 = time4-time3; 
long memoryTaken2 = freeMemory3 - freeMemory4; 
System.out.println("Concat method :" + "Time taken =" + timetaken2 + 
        " Memory Consumed =" + memoryTaken2); 

quả

Concat operator: Time taken = 31; Memory Consumed = 2259096 
Concat method : Time taken = 16; Memory Consumed = 299592 

Nếu concat() là nhanh hơn so với các nhà điều hành sau đó khi chúng ta nên sử dụng nối hành (+)?

+1

Đọc: http://stackoverflow.com/questions/693597/is-there-a-difference-between-string-concat-and-the-operator-in-java và http://stackoverflow.com/questions/47605/java-string-concatenation –

+0

Về điều duy nhất có vẻ khác nhau là khi chuỗi bạn thêm vào có độ dài bằng 0 nó chỉ cho bạn trở lại bản gốc thay vì tạo một Chuỗi mới. Toán tử + có thể tốn kém một chút ... nếu bạn đang thực hiện hàng trăm hoặc hàng nghìn hoạt động xây dựng chuỗi, hãy nhìn vào StringBuffer.append(). Nó là phổ biến để xem một phương thức xây dựng một StringBuffer và sau đó trả về hoặc sử dụng theBuffer.toString() ở cuối. –

+0

@PankajKumar tốt, bạn có thể muốn StringBuilder thay vì StringBuffer – ymajoros

Trả lời

30

Phương pháp concat luôn tạo ra một Chuỗi mới với kết quả của phép nối.

Toán tử cộng được hỗ trợ bởi việc tạo StringBuilder, nối tất cả các giá trị String bạn cần và tiếp tục gọi hàm toString().

Vì vậy, nếu bạn cần nối hai giá trị, concat() sẽ là lựa chọn tốt hơn. Nếu bạn cần ghép nối 100 giá trị, bạn nên sử dụng toán tử cộng hoặc sử dụng rõ ràng StringBuilder (ví dụ: trong trường hợp phụ thêm trong chu kỳ).

+4

Nhận xét sau của bạn chỉ đúng đối với tất cả các chuỗi nối trong cùng một biểu thức **. Vì vậy, một 'StringBuilder' được sử dụng cho' x = a + b + c' (giả sử tất cả là 'String'), nhưng hai 'StringBuilder' được sử dụng cho' x = a + b; x + = c; '. –

+1

Là phụ lục cho câu trả lời của Artem, [this] (http://www.znetdevelopment.com/blogs/2009/04/06/java-string-concatenation/) liên kết, dường như là một bài đăng trên blog từ phía sau ' 09 về câu hỏi cụ thể này. Hy vọng rằng liên kết sẽ cung cấp thêm ngữ cảnh cho các câu trả lời và nhận xét mà Artem và TJ đã cung cấp, mặc dù tôi không thể xác minh các xác nhận được đưa ra trong bài viết vì tôi không phải là chuyên gia về Java ... – blahman

+2

Don ' t bạn có nghĩa là 'sử dụng rõ ràng StringBuilder' –

-2

Thực ra, cả hai đều giống nhau. Nếu bạn thấy mã số của concat(String paramString), nó sẽ trả về một đối tượng chuỗi mới và trong toán tử (+) nó cũng sẽ tạo ra một đối tượng chuỗi mới.

Nếu bạn không muốn tạo đối tượng mới, hãy sử dụng trình tạo chuỗi để nối hai chuỗi.

+0

Đối với (+) nó chủ yếu là không đúng – dantuch

-1

Nói chung, thực tiễn không tốt là ghép nối các chuỗi với + và với concat(). Nếu bạn muốn tạo một String sử dụng StringBuilder thay thế.

+0

Điều này rõ ràng là một câu trả lời sai. Có nhiều trường hợp chúng ta nên sử dụng + hoặc concat() thay vì StringBuilder/StringBuffer. –

+0

Các trường hợp cho thấy trong câu hỏi đã được nối chuỗi trong một vòng lặp, trong trường hợp đó tôi tin rằng StringBuilder là cách tốt nhất để đi, không chỉ trong Java. – Felype

3

Tôi tin rằng 'phong cách' của việc ghép nối sẽ tạo sự khác biệt.

Đối với concat(), nó tạo nội bộ một bộ đệm mảng char mới và trả về một chuỗi mới dựa trên mảng char đó.

Đối với toán tử +, trình biên dịch thực tế dịch nó để sử dụng StringBuffer/StringBuilder. Do đó, nếu bạn nối hai chuỗi, concat() chắc chắn là một lựa chọn tốt hơn vì số lượng đối tượng được tạo chỉ là kết quả String (và bộ đệm char được sử dụng bên trong), trong khi sử dụng toán tử + sẽ được dịch sang :

result = strA + strB; 
-- translate to --> 
result = new StringBuilder(strA).append(strB).toString(); 

Một phiên bản StringBuilder bổ sung được tạo.

Tuy nhiên, nếu bạn đang nối, ví dụ năm chuỗi trong một hàng, mỗi concat() sẽ tạo đối tượng Chuỗi mới. Trong khi sử dụng toán tử +, trình biên dịch sẽ dịch câu lệnh thành một StringBuilder với nhiều hoạt động nối thêm.Nó chắc chắn là tiết kiệm rất nhiều trường hợp đối tượng tạm thời không cần thiết:

result = strA + strB + strC + strD + strE; 
-- translate to --> 
result = new StringBuilder(strA).append(strB).append(strC).append(strD).append(strE).toString(); 
+0

Điểm hòa vốn là khoảng bốn dây; hiệu quả tương đối của '(String.valueOf (strA) .concat (strB)) concat (String.valueOf (strC) .concat (strD))' so với việc sử dụng một trình xây dựng chuỗi là khoảng một tung lên. Đối với tối đa tám chuỗi, nối có thể chậm hơn, nhưng không bao giờ quá lớn, và có thể nhanh hơn trong trường hợp nó quan trọng (nó sẽ kết thúc sao chép từng ký tự chính xác ba lần; 'StringBuilder' sẽ sao chép từng ký tự hai lần nếu nó không bao giờ phải mở rộng, nhưng nếu dây là mở rộng lớn có thể sẽ được yêu cầu). – supercat

0

Bạn có thể luôn sử dụng + nếu chỉ có bạn mới sử dụng> = Java 1.5 và bạn không tuyên bố chuỗi cơ sở của bạn (mà bạn muốn nối) bên ngoài vòng lặp. Trong Java 1.5 nó dẫn đến việc tạo ra new StringBuilder và làm việc trên nó cho đến khi chuỗi của bạn hoàn tất. Đó là cách nhanh nhất.

Dù sao - nếu bạn đang trong vòng lặp (và ghép các chuỗi với +) - mỗi lần lặp của vòng lặp tạo ra một new StringBuilder - đó không phải là ý tưởng hay nhất. Vì vậy, đây là nơi bạn nên sử dụng các lớp học StringBuilder hoặc StringBuffer (chủ đề an toàn).

Nói chung, liên kết này câu trả lời rõ ràng câu hỏi của bạn, và cung cấp cho bạn kiến ​​thức đầy đủ:

http://littletutorials.com/2008/07/16/stringbuffer-vs-stringbuilder-performance-comparison/

0

Mặc dù cả hai người điều khiển và phương pháp được đưa ra đầu ra tương tự, cách họ làm việc trong nội bộ khác.

Phương thức concat() chỉ ghép nối str1 với str2 và xuất ra một chuỗi, hiệu quả hơn đối với một số lượng nhỏ các kết nối.

Nhưng với nhà điều hành nối '+', str1+=str2; sẽ được hiểu là str1 = new StringBuilder().append(str1).append(str2).toString();

Bạn có thể sử dụng phương pháp concat khi sử dụng số chuỗi ít hơn để nối. Nhưng phương thức StringBuilder sẽ nhanh về mặt hiệu suất, nếu bạn đang sử dụng một số lượng lớn các chuỗi.

+0

Xây dựng một trình xây dựng chuỗi và sử dụng nó nhiều lần là tốt cho hiệu suất, nhưng tạo một trình xây dựng chuỗi, sử dụng nó để tham gia ít hơn bốn chuỗi, và sau đó từ bỏ nó là phản tác dụng. Thật không may, trình biên dịch thường sử dụng và từ bỏ các nhà xây dựng chuỗi sau khi sử dụng chúng để nối hai chuỗi. – supercat

7

Thử nghiệm của bạn cần chạy trong ít nhất 2 giây với mỗi vòng lặp trong một phương thức riêng biệt có ý nghĩa. Thử nghiệm ngắn có thể khó khăn để tái tạo và so sánh. Từ thời gian của bạn, có vẻ như bạn đang sử dụng Windows (nghĩa là vì bạn có thời gian là 16 và 31 mili giây), hãy thử System.nanoTime() thay thế. Khi vòng lặp của bạn lặp lại trên 10.000 lần, toàn bộ phương thức được biên dịch. Điều này có nghĩa là phương pháp sau của bạn đã được biên dịch khi nó được bắt đầu.

Trong câu trả lời cho câu hỏi của bạn, concat nhanh hơn khi thêm hai chuỗi. Tuy nhiên, nó đi kèm với một đánh máy và khái niệm trên cao mà có khả năng là lớn hơn nhiều so với CPU bạn lưu. Ngay cả dựa trên các thử nghiệm của bạn lặp lại 100.000 lần nó tiết kiệm ít hơn 15 ms, nhưng nó chi phí bạn đến nay, nhiều hơn so với thời gian của bạn (mà có khả năng được giá trị hơn) Bạn có thể tìm thấy trong một phiên bản tương lai của JVM, sự khác biệt được tối ưu hóa luôn và độ phức tạp của mã của bạn vẫn còn đó.


EDIT: Tôi không nhận thấy kết quả bộ nhớ bị nghi ngờ.

String str = null; 

//------------Using Concatenation operator------------- 
long time1 = System.currentTimeMillis(); 
long freeMemory1 = Runtime.getRuntime().freeMemory(); 
for (int i = 0; i < 10000; i++) { 
    str = "Hi"; 
    str = str + " Bye"; 
} 
long time2 = System.currentTimeMillis(); 
long freeMemory2 = Runtime.getRuntime().freeMemory(); 

long timetaken1 = time2 - time1; 
long memoryTaken1 = freeMemory1 - freeMemory2; 
System.out.println("Concat operator :" + "Time taken =" + timetaken1 + " Memory Consumed= " + memoryTaken1); 

str = null; 
//------------Using Concat method------------- 
long time3 = System.currentTimeMillis(); 
long freeMemory3 = Runtime.getRuntime().freeMemory(); 
for (int j = 0; j < 10000; j++) { 
    str = "Hi"; 
    str = str.concat(" Bye"); 

} 
long time4 = System.currentTimeMillis(); 
long freeMemory4 = Runtime.getRuntime().freeMemory(); 

long timetaken2 = time4 - time3; 
long memoryTaken2 = freeMemory3 - freeMemory4; 
System.out.println("Concat method :" + "Time taken =" + timetaken2 + " Memory Consumed= " + memoryTaken2); 

in khi chạy với -XX:-UseTLAB -mx1g

Concat operator :Time taken =12 Memory Consumed= 1291456 
Concat method :Time taken =7 Memory Consumed= 560000 

làm cho tỷ lệ sử dụng bộ nhớ khoảng 2: 1. Trong câu hỏi ban đầu kết quả thay đổi mỗi khi bạn chạy nó, đôi khi các .concat() xuất hiện để sử dụng nhiều hơn.

+0

"nhưng nó chi phí bạn đến nay, nhiều hơn so với thời gian của bạn (mà có khả năng được giá trị hơn)" ở đây chi phí có nghĩa là đánh máy và khái niệm trên không? Nhưng nếu chúng ta bỏ qua lợi ích 15ms, người ta có thể tranh luận rằng sử dụng bộ nhớ là 1/10 –

+0

@Naroji Tôi không thể thấy bộ nhớ là 1/10, 15ms là thời gian cần để nhấn một phím và thực sự tầm thường thời gian phát triển. –

+0

bộ nhớ được tiêu thụ là 1/10, như đã đề cập trong câu hỏi. Toán tử concat: Thời gian thực hiện = 31 Memory Consumed = "2,259,096" Phương thức concat: Thời gian thực hiện = 16 Memory Consumed = "299,592" –

9

Thực tế s1 + s2 và s1.concat (s2) rất khác nhau.

s1 + s2 được chuyển đổi bởi javac vào

(new StringBuilder(String.valueOf(s1)).append(s2).toString(); 

Bạn có thể nhìn thấy nó nếu bạn dịch ngược .class. Cấu trúc này không hiệu quả lắm; nó bao gồm tối đa ba phân bổ char [] mới và ba hoạt động sao chép [char].

s1.concat (s2) luôn là một trong new char [] + một bản sao hoạt động, xem String.java

public String concat(String str) { 
    int otherLen = str.length(); 
    if (otherLen == 0) { 
     return this; 
    } 
    char buf[] = new char[count + otherLen]; 
    getChars(0, count, buf, 0); 
    str.getChars(0, otherLen, buf, count); 
    return new String(0, count + otherLen, buf); 
} 

Lưu ý rằng new String (int, int, char []) là gói Chuỗi của tin constructor. Nó sử dụng char buf [] trực tiếp, mà không cần sao chép thông thường để đảm bảo khả năng ẩn của buf đối với tính bất biến String.

+0

Tôi tự hỏi tại sao javac sử dụng 'StringBuilder' ngay cả khi kết hợp ít hơn bốn chuỗi? Tôi sẽ nghĩ 'String.valueOf (strA) .concat (strB) .concat (strC)' sẽ tạo ra mã nhỏ gọn hơn và - cho mọi kết hợp độ dài chuỗi - nhanh hơn những gì 'strA + strB + strC' thực sự tạo ra, trừ khi JITter thay thế mã lệnh gọi 'StringBuilder' với một cái gì đó hiệu quả hơn. – supercat