String, StringBuffer ve StringBuilder


Yanıtlar:


378

Değişebilirlik Farkı:

Stringise değişmez onların değerlerini değiştirmeye çalışırsanız, başka bir nesne ise, oluşturulan alır, StringBufferve StringBuildervardır değişken onların değerlerini değiştirebilir böylece.

İplik Güvenliği Farkı:

Arasındaki fark StringBufferve StringBuilderolmasıdır StringBufferparçacığı güvenlidir. Bu nedenle, uygulamanın yalnızca tek bir iş parçacığında çalıştırılması gerektiğinde kullanmak daha iyidir StringBuilder. StringBuilderdaha verimlidir StringBuffer.

durumlar:

  • StringDizeniz değişmeyecekse, nesne değiştirilemediğinden bir String sınıfı kullanın .
  • Dizeniz değişebiliyorsa (örnek: dizenin yapımındaki birçok mantık ve işlem) ve yalnızca tek bir iş parçacığından erişilirse, a kullanılarak StringBuilderyeterince iyidir.
  • Dizeniz değişebiliyorsa ve birden çok iş parçacığından erişilebiliyorsa, iş parçacığı güvenliğiniz için bir StringBufferçünkü StringBufferzaman uyumludur.

16
Ayrıca, mantık işlemleri için String kullanmak oldukça yavaştır ve JVM String'i bayt kodunda bir StringBuffer'a dönüştürdüğü için hiç tavsiye edilmez. Bir çok ek yükü String'den StringBuffer'a ve sonra tekrar String'e dönüştürülür.
Pieter van Niekerk

2
Böylece Stringsdeğeri değiştirdiğimizde başka bir nesne yaratılır. Eski nesne referansı, tarafından GCtoplanan çöpün toplanabilmesi için mi yoksa çöp toplanabiliyor mu?
Harsh Vardhan

@PietervanNiekerk Mantık işlemleri ile ne demek istiyorsun?
emlai

mantık işlemleri demek temel String olanlar, Şimdi sormak istiyorum bir şey, @Peter tarafından belirtildiği gibi biz her durumda String yerine StringBuffer kullanmaya başlamalı mı yoksa bazı özel durumlar var mı?
JavaDragon

@bakkal Can Bütün yöntemleri kullanmak Stringile StringBuilder?
roottraveller

47
  • StringDeğişmez bir yapı uygun olduğunda kullanırsınız ; a'dan yeni bir karakter dizisi elde etmek String, CPU zamanı veya bellekte kabul edilemez bir performans cezası taşıyabilir (veriler kopyalanmadığı için alt dizeleri elde etmek CPU verimlidir, ancak bu potansiyel olarak çok daha büyük miktarda veri tahsis edilebileceği anlamına gelir).
  • Sen kullanmak StringBuilderEğer bir değişken karakter dizisini yaratmak için genellikle bir arada birkaç karakter dizilerini bitiştirmek gerektiğinde.
  • Kullanacağınız StringBufferaynı koşullarda kullanırsınız StringBuilder, ancak temel dizede yapılan değişiklikler eşitlendiğinde (birkaç iş parçacığı dize arabelleğini okuduğunda / değiştirdiğinden).

Burada bir örneğe bakın .


2
özlü, ancak eksik, StringBuilder / Buffer kullanmanın temel nedenini kaçırır ve bu da normal String birleştirme davranışının yeniden tahsisini ve dizi kopyasını azaltmak veya ortadan kaldırmaktır.

1
"Değişmez dizelerle uğraşırken String kullanırsınız" - mantıklı değil. Dize Örnekleri değiştirilemez, bu nedenle yorum "Değişmezlik nedeniyle bellek kullanımı önemli olmadığında Dize Kullan" yazmalıdır. Kabul edilen cevap, temelleri oldukça iyi kapsar.
fooMonster

28

Temeller:

Stringdeğişmez bir sınıftır, değiştirilemez. StringBuildereklenebilir, değiştirilebilen veya kaldırılabilen ve sonuçta a'ya dönüştürülebilen değiştirilebilir bir sınıftır String StringBuffer.StringBuilder

StringBuilderNesnenize erişen tek bir iş parçacığının olduğu her durumda tercih etmelisiniz .

Ayrıntılar:

Ayrıca StringBuilder/Bufferssihir olmadığını, sadece Array'ı destek nesnesi olarak kullandıklarını ve Array'ın dolduğunda yeniden tahsis edilmesi gerektiğini unutmayın. Emin olun ve StringBuilder/Bufferher .append()çağrıldığında sürekli olarak yeniden boyutlandırılmaları gerekmeyen yerlerde nesnelerinizi yeterince büyük oluşturun .

Yeniden boyutlandırma çok dejenere olabilir. Temel olarak Array Array'ı her genişletilmesi gerektiğinde mevcut boyutunun 2 katına göre yeniden boyutlandırır. Bu, büyük miktarlarda RAM tahsis edilmesine ve StringBuilder/Buffersınıflar büyümeye başladığında kullanılmamasına neden olabilir .

Java perde arkasında String x = "A" + "B";kullanır StringBuilder. Yani basit vakalar için kendi davalarınızı ilan etmenin bir yararı yoktur. Ancak String, 4k'den küçük olan büyük nesneler oluşturuyorsanız, bildirme StringBuilder sb = StringBuilder(4096);, birleştirme işleminden veya yalnızca 16 karakterden oluşan varsayılan kurucuyu kullanmaktan çok daha etkilidir . Eğer String10k'dan az olacaksanız, güvenli olmak için yapıcı ile 10k değerine başlatın . Ancak 10k olarak başlatılırsa, 10k'dan fazla 1 karakter yazarsanız, yeniden tahsis edilir ve 20k diziye kopyalanır. Bu yüzden yüksek başlatmak düşükten daha iyidir.

Otomatik yeniden boyutlandırma durumunda, 17. karakterde destek Array yeniden tahsis edilir ve 32 karaktere kopyalanır, 33. karakterde bu tekrar olur ve Array'ı yeniden tahsis edip 64 karaktere kopyalarsınız. Bunun bir çok yeniden tahsis ve kopyaya nasıl yozlaştığını görebilirsiniz, bu StringBuilder/Bufferda ilk etapta kullanmaktan kaçınmaya çalıştığınız şeydir .

Bu, AbstractStringBuilder için JDK 6 Kaynak kodundan

   void expandCapacity(int minimumCapacity) {
    int newCapacity = (value.length + 1) * 2;
        if (newCapacity < 0) {
            newCapacity = Integer.MAX_VALUE;
        } else if (minimumCapacity > newCapacity) {
        newCapacity = minimumCapacity;
    }
        value = Arrays.copyOf(value, newCapacity);
    }

En iyi uygulama, StringBuilder/Bufferelden ne kadar büyük Stringolacağını bilmiyorsanız ihtiyacınız olacağını düşündüğünüzden biraz daha büyük başlatmaktır, ancak tahmin edebilirsiniz. İhtiyacınız olandan biraz daha fazla bellek ayırma işlemi, birçok yeniden ayırma ve kopyadan daha iyi olacaktır.

Ayrıca , çoğu durumda sadece kaçınmaya çalıştığınız dejenere yeniden ayırma ve kopyalama döngüsünü başlatacak olan String + 16 karakterlerinin boyutunu ayıracak StringBuilder/Bufferşekilde bir a ile Stringbaşlamaya dikkat edin. Aşağıdakiler doğrudan Java 6 kaynak kodundan alınmıştır.

public StringBuilder(String str) {
    super(str.length() + 16);
    append(str);
    }

Şans eseri, StringBuilder/Bufferoluşturduğunuz ve oluşturucu yapıcıyı kontrol edemediğiniz bir örnekle sonuçlanırsanız , dejenere yeniden tahsis ve kopyalama davranışından kaçınmanın bir yolu vardır. Sonuçlarınızın sığacağından .ensureCapacity()emin olmak istediğiniz boyutta arayın String.

Alternatifler:

Bir not olarak, eğer gerçekten ağır String bina ve manipülasyon yapıyorsanız , Halatlar olarak adlandırılan çok daha performans odaklı bir alternatif var .

Başka bir alternatif, StringListalt sınıflandırma yoluyla bir uygulama oluşturmak ve listenin ArrayList<String>her .append()ve diğer mutasyon işlemlerindeki karakter sayısını izlemek için sayaçlar eklemek , daha sonra tam olarak ihtiyacınız olan boyuttan .toString()bir tane oluşturmak ve listeyi oluşturmak ve oluşturmak için geçersiz kılmaktır . StringBuilderçıktı, hatta StringBuilderbir örnek değişkeni yapabilir ve sonuçları 'önbellek' .toString()ve sadece bir şey değiştiğinde bunu yeniden oluşturmak zorunda.

Ayrıca String.format(), daha iyi hale getirdikçe derleyici tarafından optimize edilebilen sabit formatlı çıktı oluştururken de unutmayın .


1
Mu String x = "A" + "B";gerçekten StringBuilder olmak derlemek? Neden sadece derleme yapmaz String x = "AB";, yalnızca derleme zamanında bileşenler bilinmiyorsa bir StringBuilder kullanmalıdır.
Matt Greer

Dize sabitleri optimize edebilir, son kez bayt kodu decompiled hatırlayamıyorum, ama orada herhangi bir değişken varsa mutlaka bir StringBuilder uygulama kullanacağını biliyorum. JDK kaynak kodunu indirebilir ve kendiniz öğrenebilirsiniz. "A" + "B" kesin bir örnek.

String.format () hakkında merak ediyordum. Projelerde kullanıldığını hiç görmedim. Genellikle StringBuilder'dır. Eh, genellikle "A" + "B" + "C" çünkü insanlar tembel;) Ben sadece bir stringBuilder kullanma eğiliminde, ben sadece iki dize bitiştirilmiş olsa bile, çünkü gelecekte, belki daha fazla dize eklenir . Asla String.format () kullanmadım çünkü hangi JDK'nın tanıtıldığını hiç hatırlamadım - JDK1.5 olduğunu görüyorum, diğer seçenekler lehine kullanırım.
jamiebarrow

9

Yani, birleştirme için mi?

Gerçek dünya örneği: Diğerlerinden yeni bir dize oluşturmak istiyorsunuz .

Örneğin bir mesaj göndermek için:

sicim

String s = "Dear " + user.name + "<br>" + 
" I saw your profile and got interested in you.<br>" +
" I'm  " + user.age + "yrs. old too"

StringBuilder

String s = new StringBuilder().append.("Dear ").append( user.name ).append( "<br>" ) 
          .append(" I saw your profile and got interested in you.<br>") 
          .append(" I'm  " ).append( user.age ).append( "yrs. old too")
          .toString()

Veya

String s = new StringBuilder(100).appe..... etc. ...
// The difference is a size of 100 will be allocated upfront as  fuzzy lollipop points out.

StringBuffer (sözdizimi tam olarak StringBuilder ile aynıdır, efektler farklıdır)

hakkında

StringBuffer vs. StringBuilder

İlki eşzamanlıdır ve daha sonra değildir.

Tek bir iplik (vakaların% 90 olan) içinde birkaç kez çağırmak Yani, eğer StringBuilderçalışacak kadar o iplik kilit sahibi olmadığını görmek için durmayacak çünkü daha hızlı.

Bu nedenle, kullanılması tavsiye edilir StringBuilder(elbette aynı anda birden fazla iş parçacığına erişiminiz yoksa, bu nadirdir)

Stringbirleştirme ( + operatörünü kullanarak ) StringBuilderaltında derleyici kullanmak için derleyici tarafından optimize edilebilir , bu yüzden artık Java'nın eski günlerinde endişelenecek bir şey değil, bu herkesin her ne pahasına kaçınılması gerektiğini söylediği bir şeydi, çünkü her birleştirme yeni bir String nesnesi oluşturdu. Modern derleyiciler artık bunu yapmıyor, ancak StringBuilder"eski" bir derleyici kullanmanız durumunda bunun yerine kullanmak iyi bir uygulamadır .

Düzenle

Sadece merak edenler için, derleyicinin bu sınıf için yaptığı şey budur:

class StringConcatenation {
    int x;
    String literal = "Value is" + x;
    String builder = new StringBuilder().append("Value is").append(x).toString();
}

javap -c StringConcatenation

Compiled from "StringConcatenation.java"
class StringConcatenation extends java.lang.Object{
int x;

java.lang.String literal;

java.lang.String builder;

StringConcatenation();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   new #2; //class java/lang/StringBuilder
   8:   dup
   9:   invokespecial   #3; //Method java/lang/StringBuilder."<init>":()V
   12:  ldc #4; //String Value is
   14:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   17:  aload_0
   18:  getfield    #6; //Field x:I
   21:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   24:  invokevirtual   #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   27:  putfield    #9; //Field literal:Ljava/lang/String;
   30:  aload_0
   31:  new #2; //class java/lang/StringBuilder
   34:  dup
   35:  invokespecial   #3; //Method java/lang/StringBuilder."<init>":()V
   38:  ldc #4; //String Value is
   40:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   43:  aload_0
   44:  getfield    #6; //Field x:I
   47:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   50:  invokevirtual   #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   53:  putfield    #10; //Field builder:Ljava/lang/String;
   56:  return

}

5 - 27 arasındaki satırlar "değişmez" adlı Dize içindir

31-53 numaralı satırlar "builder" adlı Dize içindir

Fark yok, her iki dize için de aynı kod yürütülür.


2
bu gerçekten kötü bir örnek. StringBuilder'ı "Sevgili" ile başlatmak, ilk .append () öğesinin yeniden tahsis ve kopyaya neden olacağı anlamına gelir. "Normal" birleştirme üzerinde elde etmeye çalıştığınız herhangi bir verimliliği tamamen reddetmek. Daha iyi bir örnek, son String'in tüm içeriğini tutacak bir başlangıç ​​boyutuyla oluşturmak olabilir.

1
StringBuilderÖdevin sağ tarafında bir Yapılacaklar Dizesi birleştirme kullanmak genellikle iyi bir uygulama DEĞİLDİR . İyi bir uygulama, dediğiniz gibi sahnelerin arkasında bir StringBuilder kullanır. Dahası, örneğiniz "a" + "b"tek bir değişmez olarak derlenir, "ab"ancak kullanırsanız StringBuilderiki gereksiz çağrıyla sonuçlanır append().
Mark Peters

@ Mark kullanmak demek istemedim "a"+"b"ama dize birleştirme hakkında ne olduğunu söylemek için açık olarak değiştirin. Söylemediğiniz şey, bunu yapmak için neden iyi bir uygulama değil. (Modern) bir derleyici tam da bunu yapar. @fuzzy, katılıyorum, özellikle son dizenin boyutunun ne olacağını bildiğinizde (aprox).
OscarRyz

1
Özellikle kötü bir uygulama olduğunu düşünmüyorum , ama kesinlikle bunu yapmak için herhangi bir öneri istemem. Tıknaz ve okunması zor ve aşırı ayrıntılı. Ayrıca, aksi halde bir olarak derlenebilecek iki değişmezi parçaladığınız gibi, sizinki gibi hataları teşvik eder. Sadece profilleme bana bir fark yarattığını söylerse bunu kendi tarzınızda yapardım.
Mark Peters

@ Mark anladım. Ben daha çok "bir şablon gibi büyük kod yığın" ve gerçekten her normal dize değişmez düşünüyorum. Ama evet, katılıyorum, bugünlerde aynı şeyi yaptıkları için, mantıklı değil (10 yıl önce bir kod revizyonundaki bir değişikliği reddetmek için bir
sebepti

8
-------------------------------------------------- --------------------------------
                  String StringBuffer StringBuilder
-------------------------------------------------- --------------------------------                 
Depolama Alanı | Sabit Dize Havuzu Yığın Öbek
Değiştirilebilir | Hayır (değiştirilemez) Evet (değiştirilebilir) Evet (değiştirilebilir)
Konu Güvenli | Evet Evet Hayır
 Performans | Hızlı Çok yavaş Hızlı
-------------------------------------------------- --------------------------------

String performansı neden hızlı ve StringBuffer performansı çok yavaş?
gaurav

1
@gaurav kaynak kodunu okuyabilir, StringBuffer'daki tüm yöntemler synchronisedve nedeni budur .
1919'da

8

Dize Ailesi

sicim

String classKarakter dizeleri temsil eder. Java programındaki tüm dize değişmezleri "abc", bu sınıfın örnekleri olarak uygulanır.

Dize nesnelerdir değişmez onlar değiştiremezsiniz oluşturulduktan sonra. ( Dizeler sabittir )

  • String sonra bu dizeleri saklanacaktır yapıcısı veya yöntemi kullanılarak oluşturulursa Öbek Bellek yanı sıra SringConstantPool. Ancak havuza kaydetmeden önce, intern()eşittir yöntemini kullanarak havuzdaki aynı içeriğe sahip nesnenin kullanılabilirliğini kontrol etme yöntemini çağırır . Havuzda String-copy varsa referansı döndürür. Aksi takdirde, havuza String nesnesi eklenir ve başvuruyu döndürür.

    • Java dili, dize birleştirme operatörü ( +) ve diğer nesnelerin dizelere dönüştürülmesi için özel destek sağlar . Dize birleştirmesi, StringBuilder (veya StringBuffer) sınıfı ve ekleme yöntemiyle uygulanır.

    String heapSCP = new String("Yash");
    heapSCP.concat(".");
    heapSCP = heapSCP + "M";
    heapSCP = heapSCP + 777;
    
    // For Example: String Source Code 
    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }
  • Dize değişmezleri içinde saklanır StringConstantPool.

    String onlyPool = "Yash";

StringBuilder ve StringBuffer değiştirilebilir karakter dizisidir. Bu, kişinin bu nesnelerin değerini değiştirebileceği anlamına gelir. StringBuffer, StringBuilder ile aynı yöntemlere sahiptir, ancak StringBuffer'daki her yöntem iş parçacığı açısından güvenli olacak şekilde senkronize edilir.

  • StringBuffer ve StringBuilder verileri yalnızca yeni işleç kullanılarak oluşturulabilir. Böylece, Heap belleğinde saklanırlar.

  • StringBuilder örneklerinin birden çok iş parçacığı tarafından kullanılması güvenli değildir. Bu tür bir senkronizasyon gerekiyorsa, StringBuffer'ın kullanılması önerilir.

    StringBuffer threadSafe = new StringBuffer("Yash");
    threadSafe.append(".M");
    threadSafe.toString();
    
    StringBuilder nonSync = new StringBuilder("Yash");
    nonSync.append(".M");
    nonSync.toString();
  • StringBuffer ve StringBuilder., replace(int start, int end, String str)Ve gibi özel yöntemlere sahip reverse().

    Not : StringBuffer ve SringBuilder uygulama sağlar gibi değiştirilebilir Appendable Interface.


Hangisi ne zaman kullanılır.

  • Eğer bir değeri her seferinde değiştirmeyecekseniz Kullanmak daha iyidir String Class. Generics'in bir parçası olarak, Comparable<T>bir değeri Sıralamak veya karşılaştırmak istiyorsanız gidin String Class.

    //ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.Comparable
    Set<StringBuffer> set = new TreeSet<StringBuffer>();
    set.add( threadSafe );
    System.out.println("Set : "+ set);
  • Her seferinde değeri değiştirecekseniz StringBuffer'dan daha hızlı olan StringBuilder için gidin. Birden çok iş parçacığı değeri değiştiriyorsa StringBuffer için gidin.


4

Ayrıca, StringBufferiş parçacığı için güvenli, StringBuilderdeğil.

Bu nedenle, farklı iş parçacıklarının ona eriştiği gerçek zamanlı bir durumda, StringBuilderbelirsiz bir sonuç elde edilebilir.


3

Java 5 veya daha yenisini kullanıyorsanız, StringBuilderbunun yerine kullanmanız gerektiğini unutmayın StringBuffer. API belgelerinden:

JDK 5 sürümünden itibaren bu sınıf, tek bir iş parçacığı tarafından kullanılmak üzere tasarlanmış eşdeğer bir sınıfla desteklenmiştir StringBuilder. StringBuilderAynı operasyonların tüm destekliyor ancak hiçbir senkronizasyon gerçekleştirir gibi, daha hızlı olduğu gibi sınıf genellikle bu bir tercih edilerek kullanılmalıdır.

Pratikte, bunu neredeyse hiçbir zaman aynı anda birden fazla iş parçacığından kullanmazsınız, bu nedenle yapılan senkronizasyon StringBufferneredeyse her zaman gereksiz ek yüktür.


3

Şahsen, gerçek bir dünya kullanımı olduğunu sanmıyorum StringBuffer. Ne zaman bir karakter dizisini değiştirerek birden çok iş parçacığı arasında iletişim kurmak isterdim? Bu hiç de kullanışlı gelmiyor, ama belki de ışığı henüz görmedim :)


3

String ve diğer iki sınıf arasındaki fark String'in değişmez ve diğer ikisinin değiştirilebilir sınıflar olmasıdır.

Ama neden aynı amaçla iki sınıfımız var?

Sebep iş StringBufferparçacığı güvenli ve StringBuilderdeğil olmasıdır. StringBuilderyeni bir sınıftır StringBuffer Apive tanıtıldı JDK5ve tek iş parçacıklı bir ortamda çalışıyorsanız her zaman tavsiye edilir.Faster

Tüm Detaylar için http://www.codingeek.com/java/stringbuilder-and-stringbuffer-a-way-to-create-mutable-strings-in-java/


2

Java, dize sabittir. Değişmez olmak, Dize oluşturulduktan sonra değerini değiştiremeyeceğimizi kastediyoruz. StringBuffer değiştirilebilir. Bir StringBuffer nesnesi oluşturulduktan sonra, içeriği yeni bir nesne oluşturmak yerine nesnenin değerine ekleriz. StringBuilder , StringBuffer'a benzer, ancak iş parçacığı için güvenli değildir. StingBuilder yöntemleri senkronize edilmez ancak diğer Dizelerle karşılaştırıldığında Stringbuilder en hızlı çalışır. String, StringBuilder ve StringBuffer arasındaki farkı uygulayarak öğrenebilirsiniz .

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.