Thực tiễn / hiệu suất tốt nhất: trộn StringBuilder.append với String.concat


86

Tôi đang cố gắng hiểu cách thực hành tốt nhất là gì và tại sao lại nối các ký tự chuỗi và biến cho các trường hợp khác nhau. Ví dụ: nếu tôi có mã như thế này

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String).append("CCCCCCCCCCC").append(D_String)
    .append("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .append("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");

Đây có phải là cách để làm điều đó? Từ bài đăng này , tôi nhận thấy rằng +toán tử trên Strings tạo một phiên bản mới của StringBuilder, nối các toán hạng và trả về một chuyển đổi Chuỗi, có vẻ như nhiều công việc hơn là chỉ gọi .append(); vì vậy nếu điều đó là sự thật, thì điều đó không còn nữa. Nhưng những gì về String.concat()? Nó có thích hợp để sử dụng .append()cho mọi từ nối không? Hay chỉ dành cho các biến và các ký tự có thể nối thêm vào .concat()?

StringBuilder sb = new StringBuilder("AAAAAAAAAAAAA")
    .append(B_String.concat("CCCCCCCCCCC")).append(D_String
    .concat("EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE")
    .concat("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));

Các quy tắc chung cho các phương pháp hay nhất và hiệu suất để giải quyết những tình huống này là gì? Giả định của tôi có đúng trên không +và nó thực sự không nên được sử dụng?


Tôi nghĩ về cơ bản bạn đã có nó. Các ý kiến ​​khác nhau về việc liệu String + "thực sự không nên được sử dụng". Vấn đề là rằng bạn hiểu những hậu quả
ControlAltDel

Câu trả lời:


184

+ nhà điều hành

String s = s1 + s2

Đằng sau cảnh này được dịch thành:

String s = new StringBuilder(s1).append(s2).toString();

Hãy tưởng tượng nó thêm bao nhiêu công việc nếu bạn có s1 + s2ở đây:

stringBuilder.append(s1 + s2)

thay vì:

stringBuilder.append(s1).append(s2)

Nhiều chuỗi với +

Cần lưu ý rằng:

String s = s1 + s2 + s3 + ... +sN

được dịch thành:

String s = new StringBuilder(s1).append(s2).append(s3)...apend(sN).toString();

concat()

String s = s1.concat(s2);

Stringtạo char[]mảng có thể phù hợp với cả hai s1s2. Bản sao s1s2nội dung vào mảng mới này. Trên thực tế đòi hỏi ít công việc hơn sau đó +điều hành.

StringBuilder.append()

Duy trì một char[]mảng nội bộ phát triển khi cần thiết. Không có phần bổ sung nào char[]được tạo ra nếu phần bên trong đủ lớn.

stringBuilder.append(s1.concat(s2))

cũng hoạt động kém vì s1.concat(s2)tạo thêm một char[]mảng và sao chép s1s2nó chỉ để sao chép nội dung mảng mới đó vào nội bộ StringBuilder char[].

Điều đó đang được nói rằng bạn nên sử dụng append()mọi lúc và nối các chuỗi thô (đoạn mã đầu tiên của bạn là đúng).


Cảm ơn sự giúp đỡ của bạn và lời giải thích chuyên sâu; đó là những gì tôi thực sự cần.
Nick Rolando

12
Mặc dù các phiên bản mới hơn của trình biên dịch tự động tối ưu hóa toán tử + cho một trình tạo chuỗi, nhưng không nhất thiết phải là một điều tốt khi giả định nó sẽ như các phiên bản cũ hơn không. Có một chủ đề rất quan trọng đang bị bỏ qua trong toàn bộ cuộc thảo luận này mà thực sự là một trong những mục đích chính của StringBuilder là nhóm chuỗi. Việc sử dụng trình tạo chuỗi giữ mọi thứ dưới dạng char [] và không tạo Chuỗi trung gian như toán tử + đã làm trước khi tối ưu hóa trình biên dịch (được sử dụng để chỉ thực hiện một concat). Sử dụng concat tạo ra một đối tượng Chuỗi trung gian được lưu trong bộ đệm nhưng không được sử dụng.
LINEMAN78

Vì vậy, nếu tôi đang thực hiện một câu lệnh một lần (không phải nhiều câu lệnh trên một phương thức) nối trên một số chuỗi khác nhau. Sẽ không sao khi sử dụng +trên các đối tượng Chuỗi thay vì tạo một StringBuildercho nối một lần này, vì về cơ bản nó sẽ làm điều tương tự?
Nick Rolando

1
Và nếu tôi chỉ muốn nối một ký tự, thì tốt hơn là sử dụng .append ('\ n') thay vì .append ("\ n")? Vì một ký tự là một kiểu nguyên thủy, và một chuỗi là một Đối tượng?
vrwim

3
Phiên bản Java 2 hiệu quả : Sử dụng toán tử nối chuỗi lặp đi lặp lại để nối n chuỗi đòi hỏi thời gian bậc hai tính bằng n. Vậy nó có còn liên quan không?
gkiko

16

Trình biên dịch tối ưu hóa + nối.

Vì thế

int a = 1;
String s = "Hello " + a;

được chuyển thành

new StringBuilder().append("Hello ").append(1).toString();

Có một chủ đề tuyệt vời ở đây giải thích lý do tại sao bạn nên sử dụng toán tử +.


3
Trình biên dịch thực sự sẽ tối ưu hóa điều đó thành String s = "Hello World";vì bạn sử dụng các ký tự.
ColinD

@ColinD: +1. Chỉ cần sửa đổi đoạn mã của tôi.

3

Việc tối ưu hóa được thực hiện tự động bởi trình biên dịch.

Trình biên dịch Java2 sẽ tự động chuyển đổi như sau:

String s = s1 + s2; 

đến

String s = (new StringBuffer()).append(s1).append(s2).toString();

Lấy trực tiếp từ Các phương pháp hay nhất về Java trên trang web Oracles.


2

Bạn luôn nên sử dụng append.

concattạo một Chuỗi mới để nó đẹp như +tôi nghĩ.

Nếu bạn concathoặc sử dụng +với 2 Chuỗi cuối cùng, JVM có thể thực hiện tối ưu hóa, do đó, nó giống như thực hiện chắp thêm trong trường hợp này.


1

Nếu bạn nối chính xác hai Chuỗi, hãy sử dụng String.concat (tạo một Chuỗi mới bằng cách tạo một mảng char mới phù hợp với cả hai Chuỗi và sao chép cả hai mảng char của Chuỗi vào nó).

Nếu bạn nối nhiều (nhiều hơn hai) Chuỗi trong một dòng, hãy sử dụng + hoặc StringBuilder.append, điều đó không thành vấn đề, vì trình biên dịch chuyển đổi + thành StringBuilder.append. Điều này tốt cho nhiều Chuỗi vì nó duy trì một mảng ký tự phát triển khi cần thiết.

Nếu bạn nối nhiều Chuỗi trên nhiều dòng, hãy tạo một StringBuilder và sử dụng phương thức append-method. Cuối cùng, khi bạn hoàn tất việc nối các Chuỗi vào StringBuilder, hãy sử dụng phương thức .toString () - để tạo một Chuỗi từ nó. Đối với nối trong nhiều dòng, cách này nhanh hơn phương pháp thứ hai, vì phương thức thứ hai sẽ tạo một StringBuilder mới trên mỗi dòng, nối các Chuỗi và sau đó ép kiểu trở lại String, trong khi phương pháp thứ ba chỉ sử dụng một StringBuilder cho toàn bộ.


0

Sử dụng +toán tử là cách tốt nhất, nó cũng đơn giản và dễ đọc.

Ngôn ngữ Java cung cấp hỗ trợ đặc biệt cho toán tử nối chuỗi (+) và chuyển đổi các đối tượng khác thành chuỗi. Việc nối chuỗi được thực hiện thông qua lớp StringBuilder (hoặc StringBuffer) và phương thức nối thêm của nó.

Tài liệu ngoại tuyến: https://docs.oracle.com/javase/8/docs/api/java/lang/String.html


0

ở mức mã byte không có khác biệt và chúng tôi không làm ảnh hưởng đến hiệu quả ở đó. Trong trường hợp thực thi mức mã byte, nó phải thông qua phương pháp nạp chồng toán tử không nội tuyến cho + bằng cách gọi append. thì ở mức hợp ngữ (Java được viết bằng C và C tạo ra các hợp ngữ tương tự như hợp ngữ, sẽ có thêm lệnh gọi thanh ghi để lưu trữ + lệnh gọi phương thức trong ngăn xếp và sẽ có thêm lần đẩy. (trong thực tế, trình biên dịch chéo có thể tối ưu hóa + toán tử gọi, trong trường hợp đó, không có gì khác biệt với hiệu quả.)

Đó là một thực hành tốt để có một cách để tăng khả năng đọc. :)


0

Cá nhân tôi thích trình định dạng chuỗiStrings.format() một dòng, đơn giản, dễ đọc .

String b = "B value";
String d = "D value";
String fullString = String.format("A %s C %s E F", b, d);
// Output: A B value C D value E F

0

Tất cả các câu trả lời là khá tốt và giải thích. Nhưng tôi cảm thấy việc khám phá các kỹ thuật nối chuỗi khác cũng sẽ hữu ích như - Guava Joiner, Streams, String.format, v.v.

Để biết thông tin chi tiết đầy đủ về hiệu suất của từng kỹ thuật nối java-string-concatenation-which-way-is-best .

Trong Tóm tắt, hiệu suất nối thay đổi tùy theo không. của các chuỗi để nối. Ví dụ - để nối các chuỗi 1-10, các kỹ thuật này hoạt động tốt nhất - StringBuilder, StringBuffer và Plus Operator. Và để nối 100 chuỗi - Guava Joiner, thư viện stringUtils của apache cũng hoạt động tuyệt vời.

Vui lòng đi qua blog trên. Nó thực sự giải thích hiệu quả hoạt động rất tốt.

Cảm ơn.

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.