En iyi uygulamalar / performans: StringBuilder.append'i String.concat ile karıştırma


87

En iyi uygulamanın ne olduğunu ve dize değişmezlerini ve değişkenleri farklı durumlar için neden birleştirdiğini anlamaya çalışıyorum. Örneğin, böyle bir kodum varsa

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

Bunu yapmanın yolu bu mu? Gönderen bu yazı , bunu fark +Strings üzerinde operatör, StringBuilder yeni bir örneğini oluşturur işlenen birleştirir ve sadece çağıran çok daha fazla iş gibi görünen bir dize dönüşüm, döner .append(); bu doğruysa, bu söz konusu bile olamaz. Peki ya ne olacak String.concat()? .append()Her birleştirme için kullanmak uygun mudur ? Ya da sadece değişkenler için ve değişmez değerler eklenmeye uygun .concat()mu?

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

En iyi uygulamalar için genel kurallar ve bu durumlardan vazgeçme performansı nelerdir? Varsayımım doğru mu +ve gerçekten kullanılmamalı mı?


Sanırım temelde anladın. Fikirler, String + "gerçekten kullanılmaması gerektiği" konusunda farklılık gösterir. Önemli olan, sonuçlarını anladığınızdır
ControlAltDel

Yanıtlar:


185

+ Şebeke

String s = s1 + s2

Perde arkasında bunun tercümesi:

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

s1 + s2Burada varsa ne kadar fazla iş kattığını bir düşünün :

stringBuilder.append(s1 + s2)

onun yerine:

stringBuilder.append(s1).append(s2)

Birden çok dize +

Unutulmamalıdır ki:

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

şu dile çevrildi:

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

concat()

String s = s1.concat(s2);

Stringyaratan char[]hem sığabilecek dizi s1ve s2. Bu yeni diziye kopyalar s1ve s2içerikler. Aslında +operatörden daha az iş gerektirir .

StringBuilder.append()

char[]Gerektiğinde büyüyen dahili bir diziyi korur . char[]İç kısım yeterince büyükse fazlalık yaratılmaz.

stringBuilder.append(s1.concat(s2))

performans da kötüdür çünkü s1.concat(s2)fazladan bir char[]dizi oluşturur s1ve s2ona sadece yeni dizi içeriğini dahili olarak kopyalar StringBuilder char[].

Her append()zaman kullanmanız ve ham dizeler eklemeniz gerektiği söyleniyor (ilk kod pasajınız doğrudur).


Yardımınız ve ayrıntılı açıklama için teşekkürler; gerçekten ihtiyacım olan şey bu.
Nick Rolando

12
Derleyicinin daha yeni sürümleri, + operatörünü otomatik olarak bir dize oluşturucuya optimize etse de, eski sürümlerin yapmadığı gibi olacağını varsaymak her zaman iyi bir şey değildir. Bu tartışmanın tamamında göz ardı edilen çok önemli bir konu var ki bu aslında string havuzu olan StringBuilder'ın ana amaçlarından biri. Bir dize oluşturucu kullanmak her şeyi bir char [] olarak tutar ve derleyici optimizasyonlarından önce + operatörünün yaptığı gibi bir ara String oluşturmaz (sadece bir concat yapmak için kullanılır). Concat kullanılması, önbelleğe alınan ancak kullanılmayan bir ara String nesnesi oluşturur.
LINEMAN78

Bu nedenle , birkaç farklı dizede tek seferlik bir ifade (bir yöntemde birden fazla ifade değil) birleştirme yapıyorsam . Kullanımı sakınca yoktur +yerine yaratma nesneleri String üzerinde StringBuildertemelde aynı şeyi yapacağız, çünkü bu tek seferlik Ulama için?
Nick Rolando

1
Ve sadece bir karakteri birleştirmek istersem, .append ("\ n") yerine .append ('\ n') kullanmak daha mı iyi? Bir karakter ilkel bir tür ve String bir Nesne mi?
vrwim

3
Etkili Java 2-nd sürümü : n dizeyi birleştirmek için dizgi birleştirme operatörünü tekrar tekrar kullanmak, n'de zamanın ikinci dereceden olmasını gerektirir. Öyleyse hala geçerli mi?
gkiko

16

Derleyici, + birleştirmeyi optimize eder.

Yani

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

dönüştü

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

Burada neden + operatörünü kullanmanız gerektiğini açıklayan mükemmel bir konu var .


3
Derleyici, String s = "Hello World";değişmez değerleri kullandığınız için bunu aslında optimize eder .
ColinD

@ColinD: +1. Az önce pasajımı değiştirdim.

3

Optimizasyon, derleyici tarafından otomatik olarak yapılır.

Java2 derleyicisi aşağıdakileri otomatik olarak dönüştürecektir:

String s = s1 + s2; 

-e

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

Doğrudan Oracles web sitesindeki Java Best Practices'dan alınmıştır .


2

Her zaman kullanmalısın append.

concatyeni bir String oluşturun, böylece +düşündüğüm gibi güzel olur .

Eğer siz concatveya +2 final String ile kullanıyorsanız, JVM optimizasyon yapabilir, böylece bu durumda append yapmakla aynı şey olur.


1

Tam olarak iki Dizeyi birleştirirseniz, String.concat kullanırsanız (her iki Strings'e uyan ve her iki Strings'in char dizisini de içine kopyalayan yeni bir char dizisi oluşturarak yeni bir String oluşturur).

Birden fazla (ikiden fazla) Dizeyi bir satırda birleştirirseniz, + veya StringBuilder.append kullanın, derleyici + 'yı StringBuilder.append' e dönüştürdüğünden bu önemli değildir. Gerektiğinde büyüyen bir karakter dizisi tuttuğu için bu, birden çok Dizge için iyidir.

Birden çok Dizeyi birden çok satır üzerinde birleştirirseniz, bir StringBuilder oluşturun ve append yöntemini kullanın. Sonunda, StringBuilder'a Strings eklemeyi bitirdiğinizde, onun .toString () - yönteminden bir String oluşturmak için kullanın. Birden fazla satırda birleştirmek için bu, ikinci yöntemden daha hızlıdır, çünkü ikinci yöntem her satırda yeni bir StringBuilder oluşturur, Strings'i ekler ve ardından String'e geri döndürür, üçüncü yöntem ise her şey için yalnızca bir StringBuilder kullanır.


0

Kullanım +operatörü en iyi uygulamadır, ayrıca basit ve okunabilirdir.

Java dili, dizi bitiştirme operatörü (+) ve diğer nesnelerin dizelere dönüştürülmesi için özel destek sağlar. Dize birleştirme, StringBuilder (veya StringBuffer) sınıfı ve onun ekleme yöntemi aracılığıyla uygulanır.

Resmi belge: https://docs.oracle.com/javase/8/docs/api/java/lang/String.html


0

bayt kodu seviyesinde farklı değildir ve orada verimlilikten ödün vermiyoruz. Bayt kodu seviyesinin yürütülmesi durumunda, append'i çağırarak + için satır içi olmayan operatör aşırı yükleme yönteminden geçmelidir. daha sonra assembly dili düzeyinde (Java C dilinde yazılır ve C, assembly'ye benzer derlemeler üretir, yığında depolamak için ekstra kayıt çağrısı + yöntem çağrısı olur ve ek itme olur. (gerçekte, çapraz derleyici optimize edebilir + operatörü arayın, bu durumda verimlilikle bir fark yaratmaz.)

Okunabilirliği artırmanın bir yolu olması iyi bir uygulamadır. :)


0

Ben şahsen Strings.format()okuması kolay, tek satırlık dizge biçimlendiriciyi tercih ederim .

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üm cevaplar oldukça iyi ve açıklayıcıdır. Ancak diğer dizi birleştirme tekniklerinin de yardımcı olacağını hissettim - Guava Joiner, Streams, String.format vb.

Her birleştirme tekniğinin performansı hakkında eksiksiz ayrıntılar için java-string-birleştirme-hangi-yol-en iyisidir .

Kısaca, birleştirme performansı no ile değişir. birleştirilecek dizelerin sayısı. Örneğin, 1-10 dizeyi birleştirmek için bu teknikler en iyi şekilde çalışır - StringBuilder, StringBuffer ve Plus Operator. Ve 100'lerce dizeyi birleştirmek için - Guava Joiner, apache'nin stringsUtils kitaplığı da harika çalışıyor.

Lütfen yukarıdaki blogu gözden geçirin. Performans verimliliğini gerçekten çok iyi açıklıyor.

Teşekkürler.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.