# StringBuilder vs. Stringverkettung



## Youlian (2. Aug 2007)

Hallo,

ich wollte mal dem Interesse halber nachfragen was schneller ist:


```
StringBuilder qry = new StringBuilder();
for(... 2 verschachtelte Schleifen ...) {
  qry.append("(" + columns[j] + " = '" + searchPatterns[i] + "')");
}
```

... oder ...


```
StringBuilder qry = new StringBuilder();
for(... 2 verschachtelte Schleifen ...) {
  qry.append("(");
  qry.append(columns[j]);
  qry.append(" = '");
  qry.append(searchPatterns[i]);
  qry.append("')");
}
```

Das '+' für die Stringverkettung ist in Java eine der wenigen (der einzige?! mit fällt grad keiner anderer ein ^^) überladene Operator.
Weiß jemand welche der beiden Methoden schneller ist? - Ich glaube mich dunkel daran zu erinnern, irgendwo einmal gelesen zu haben, das man die exzessive Anwendung von Stringverkettung vermeiden soll. Da da bei jeder Verkettung ein neues String Objekt mit der größe der beiden zu verkettenden angelegt wird. (Da Strings ja immutable sind)

Ist Stringverkettung also gleichzusetzen mit (Bsp aus der API):
"to".concat("get").concat("her") returns "together" ??

Ist das richtig so? - Oder doch ganz anders? ;-)
Kann mir da jemand kurz die internas erklären und vor allem: Was ist jetzt schneller?

lg
Youlian


----------



## SlaterB (2. Aug 2007)

StringBuilder ist schneller als +, das sollte klar sein,
ein StringBuilder erzeugt keine Zwischenstrings,

kannst deinen Code auch 1 Mio. mal ausführen und die Systemzeit messen,
bei deutlich weniger Strings in Mini-Anwendungen wirst du aber keinen Unterschied merken

string.concat(string) erzeugt auch Zwischenstrings wie +,
scheint das gleiche zu sein, kann ich persönlich aber nicht genau sagen


----------



## Youlian (2. Aug 2007)

Ok, Danke für die (sehr) schnelle Antwort.
Bin trotzdem noch dankbar für eine längere Ausführung oder aber auch über einen Link zum Thema.

lg
Youlian


----------



## SlaterB (2. Aug 2007)

das ist ein recht bekanntes Thema, da findet man bei google sicher einiges,
wenn es auch mit Begriffen wie String, StringBuilder, Performance etwas mühsam war:

http://www.yigg.de/15332_Java_Strings_oder_WieichmeinePerfromanceverbaue

http://java.sun.com/developer/JDCTechTips/2002/tt0305.html#tip1


----------



## mephi (2. Aug 2007)

als ich es mal getestet habe kam dabei raus dass ein StringBuilder ca doppelt so schnell ist.
ob mein test sehr aussage kräftig war kann ich nicht sagen 
bin weniger der analytiker


----------



## Wildcard (2. Aug 2007)

Je nach Anwendungsfall kann das auch 1000 mal schneller sein. Es hängt davon ab wie die Strings verkettet werden.
Eigentlich können Strings nämlich gar nicht verkettet werden, sondern es werden im schlimmsten Fall Millionen von StringBuffern instanziert.


----------



## krel (3. Aug 2007)

Wird der StringBuilder nicht intern sowieso verwendet? Habe letztens mal ne Class Datei dekompiliert und festgestellt, dass dort nur der StringBuilder verwendet wird,anstatt der "+"? 

Krel


----------



## Wildcard (3. Aug 2007)

siehe oben  :roll:


----------



## Saxony (22. Aug 2007)

Hiho,

habe das mal gestestet.


```
private static void stringPlus() {
		
    String s = "";
		
    for(int i = 100000; i > 0; i--) {
		
        s += "a";
    }
}
```

Analog dazu noch Methoden mit:


```
s.concat("a");
StringBuilder.append("a");
StringBuffer.append("a");
```

Resultat war (in millisekunden bei 100.000 bzw. 2.000.000 Durchläufen jeweils):


```
String + String (100k) : 24001
String.concat (100k) : 12094
StringBuilder (2M) : 94
StringBuffer (2M) : 141
```

Was verwundert: concat ist doch um einiges fixer als +.
Die Abweichung zwischen StringBuilder und StringBuffer liegt an der threadsicheren Implementierung des Buffers.

Ergänzung:

bei StringBuilder und StringBuffer lohnt es sich dem Konstruktor schon zu sagen wie groß man es brauch.


```
StringBuilder s = new StringBuilder(10000000);
StringBuffer s = new StringBuffer(10000000);

ohne InitialWert:
StringBuilder (10M) : 609
StringBuffer (10M) : 1296

mit InitialWert:
StringBuilder (10M) : 469
StringBuffer (10M) : 1187
```

Ohne Initialwert treten zum Beispiel bei 20M Durchgängen "Out of of Memory-Exceptions" auf, welche mit vorherigem Initialwert nicht auftreten.

Edit:
Werte für s = s.concat("a") angepasst.

bye Saxony


----------



## Wildcard (22. Aug 2007)

Bitte den gesamten Code posten, den du zum testen verwendet hast.
Mikrobenchmarks sind schwieriger zu realisieren als den meisten klar ist.
Insbesondere bei Strings ist da Vorsicht geboten.


----------



## Saxony (22. Aug 2007)

Hiho,

hier isser:


```
public class StringTester {
	
	public static void main(String[] args) {
	
		long timeStart = System.currentTimeMillis();
		stringPlus();
		System.out.println("String + String (100k) : " + (System.currentTimeMillis() - timeStart));
		timeStart = System.currentTimeMillis();
		stringConcat();
		System.out.println("String.concat (100k) : " + (System.currentTimeMillis() - timeStart));
		timeStart = System.currentTimeMillis();
		stringBuilder();
		System.out.println("StringBuilder (10M) : " + (System.currentTimeMillis() - timeStart));
		timeStart = System.currentTimeMillis();
		stringBuffer();
		System.out.println("StringBuffer (10M) : " + (System.currentTimeMillis() - timeStart));
	}
	
	private static void stringPlus() {
		
		String s = "";
		
		for(int i = 100000; i > 0; i--) {
		
			s += "a";
		}
	}
	
	private static void stringConcat() {
		
		String s = "";
		
		for(int i = 100000; i > 0; i--) {
		
			s.concat("a");
		}
	}
	
	private static void stringBuilder() {
		
		StringBuilder s = new StringBuilder(10000000);
		
		for(int i = 10000000; i > 0; i--) {
		
			s.append("a");
		}
		
		s.toString();
	}
	
	private static void stringBuffer() {
		
		StringBuffer s = new StringBuffer(10000000);
		
		for(int i = 10000000; i > 0; i--) {
		
			s.append("a");
		}
		
		s.toString();
	}
}
```

bye Saxony


----------



## Wildcard (22. Aug 2007)

Ok, der Test ist definitiv falsch.
Zwei wichtige Dinge zu beachten:

1. Du gibst der VM die Gelegenheit zu optimieren, wodurch die späteren Resultate schneller werden als die ersten und im dümmsten Fall die ganze Schleife ersetzt wird. Immer nur ein Test gleichzeitig!

2. String sind immutable, weil die VM sie munter im ganzen und partiell wiederverwertet.
concat kann davon vermutlich massiv profitieren, weil du mit String + String den Pool schon gut gefüllt hast.

Deine Ergebnisse sind IMO unbrauchbar.


----------



## Saxony (22. Aug 2007)

So naja - auch wenn ich für jede Methode eine eigene Anwendung schreibe, ändert sich nix an den Laufzeiten.

bye Saxony


----------



## Wildcard (22. Aug 2007)

Zum einen glaube ich dir nicht, das sich die Laufzeiten nicht verändern, zum anderen ist das kein praxisnahes Beispiel, weil du immer wieder den gleichen String aus dem Pool fischst und als letztes ist es sowieso ziemlich sinnlos concat, +, builder und buffer mit völlig unterschiedlichen Werten zu testen.


----------



## SlaterB (22. Aug 2007)

ihr seid ja paar Streithähne, mit so komischen Argumenten..

> 1. Du gibst der VM die Gelegenheit zu optimieren, wodurch die 
> späteren Resultate schneller werden als die ersten und im 
> dümmsten Fall die ganze Schleife ersetzt wird. Immer nur ein 
> Test gleichzeitig!

? Beispiel ?

> 2. String sind immutable, weil die VM sie munter im ganzen und 
> partiell wiederverwertet. 
> concat kann davon vermutlich massiv profitieren, weil du mit 
> String + String den Pool schon gut gefüllt hast. 

? lächerlich
dreh doch einfach die Reihenfolge um oder führe die Tests abwechselnd durch.. (damit fällt auch 'späteren Resultate schneller' weg  )

> zum anderen ist das kein praxisnahes Beispiel, weil du immer wieder den gleichen String aus dem Pool fischst 

du meinst, Java hat intern irgendeine Optimierung für concat vorgesehen, 
die es für + nicht gibt?
selbst wenn: wäre das schlimm?, geht doch gerade darum, den Unterschied darzustellen?

>  letztes ist es sowieso ziemlich sinnlos concat, +, builder und buffer mit völlig unterschiedlichen Werten zu testen

? es ist doch immer nur das eine 'a',
meinst du die Anzahlen? für + und concat ist es die gleiche,
Buffer und Builder sind eh außer Konkurrenz

der Code von Saxony hat natürlich einen gravierenden Fehler:
s.concat("a"); 
statt
s = s.concat("a"); 


richtiger ist es so (auch noch mit zufälligen Buchstaben statt nur a, das dürfte das Wegoptimieren schwer machen  ):


```
public class StringTester
{
    static int k = 30000;

    public static void main(String[] args)
    {
        stringConcat();
        stringPlus();
        stringConcat();
        stringPlus();
        stringConcat();
        stringPlus();
    }

    private static void stringPlus()
    {
        long timeStart = System.currentTimeMillis();
        String s = "";
        for (int i = k; i > 0; i--)
        {
            s += (char)(Math.random() * 200);
        }
        System.out.println("String +     : " + (System.currentTimeMillis() - timeStart));
    }

    private static void stringConcat()
    {
        long timeStart = System.currentTimeMillis();

        String s = "";
        for (int i = k; i > 0; i--)
        {

            s = s.concat(String.valueOf((char)(Math.random() * 200)));
        }
        System.out.println("String.concat: " + (System.currentTimeMillis() - timeStart));
    }
}



Ausgabe:

String.concat: 1030
String +     : 2419
String.concat: 1030
String +     : 2575
String.concat: 1014
String +     : 2528
```

irgendwie schneller ist concat also trotzdem,
wenn man a statt des Zufallsstrings nimmt, ändert sich übrigens praktisch gar nix


----------



## Saxony (22. Aug 2007)

SlaterB hat gesagt.:
			
		

> ihr seid ja paar Streithäne, mit so komischen Argumenten..



Ich streite ja gar net. 



			
				SlaterB hat gesagt.:
			
		

> der Code von Saxony hat natürlich einen gravierenden Fehler:
> s.concat("a");
> statt
> s = s.concat("a");



Danke für den Hinweis! Deswegen war mein concat so fix. Hehe!
Yep also concat ist also so 50-60% schneller als die reine "Stringaddition".

Im Endeffekt hatte ich also bis auf den Tippfehler schon den Finger drauf. 

bye Saxony


----------



## Wildcard (22. Aug 2007)

> ? Beispiel ?


Für was?


> ? lächerlich


Spitzen Argument  :toll: 


> dreh doch einfach die Reihenfolge um oder führe die Tests abwechselnd durch.. (damit fällt auch 'späteren Resultate schneller' weg


Besser noch: Ein Testlauf pro Methode, so schließt man Seiteneffekte besser aus.



> irgendwie schneller ist concat also trotzdem


Genau das lässt sich nicht pauschal schließen.
Der Compiler wandelt String + String in einen StringBuilder (welcher nach deiner Meinung ja schon ausser Konkurrenz ist :wink: ) um, während concat einfach ein neues Array allokiert in das beide Strings passen. Die Sache hängt also massiv von den Laufzeitdaten ab, weshalb ich auch darauf hinweise, dass Mikrobenchmarks immer sehr kritisch zu betrachten sind und genau überlegt sein wollen.


----------



## Saxony (22. Aug 2007)

Wildcard hat gesagt.:
			
		

> Besser noch: Ein Testlauf pro Methode, so schließt man Seiteneffekte besser aus.



Hatte ich ja schon gemacht mit gleichem Ergebnis.

Aber das glaubste mir ja net.  :?: 



			
				Wildcard hat gesagt.:
			
		

> Zum einen glaube ich dir nicht, das sich die Laufzeiten nicht verändern



 ???:L 

Dann musstes halt ma selber schreibn - vielleicht glaubste dir selber ja eher mal.  :applaus: 

bye Saxony


----------



## SlaterB (22. Aug 2007)

Wildcard hat gesagt.:
			
		

> > ? Beispiel ?
> 
> 
> Für was?


für deine Optimierungstheorien, 
es zeigt sich doch sehr deutlich, dass absolut gar nix passiert



> > irgendwie schneller ist concat also trotzdem
> 
> 
> Genau das lässt sich nicht pauschal schließen.
> Der Compiler wandelt String + String in einen StringBuilder um, während concat einfach ein neues Array allokiert in das beide Strings passen. Die Sache hängt also massiv von den Laufzeitdaten ab, weshalb ich auch darauf hinweise, dass Mikrobenchmarks immer sehr kritisch zu betrachten sind und genau überlegt sein wollen.


und was bedeutet das?
was heißt Laufzeitdaten? wieso hängt das von irgendwas ab?
wenn man das 10x ausführt, passiert 10x das gleiche, was genau soll in irgendeiner Form zu beachten sein?


dass andere VM oder andere Compiler ein ganz anderes Programm draus machen gilt natürlich für jedes Programm der Welt..
(jetzt bin ich der Streithahn, ich weiß, mach ich ja so gerne  )


----------



## Wildcard (22. Aug 2007)

> für deine Optimierungstheorien,
> es zeigt sich doch sehr deutlich, dass absolut gar nix passiert


Und diese Aussage triffst du pauschal für jeden Hotspot/JIT, ohne auch nur den Bytecode gesehen zu haben, oder die Optimierung ausgeschaltet zu haben (wobei dann wieder sehr fraglich ist, ob das Resultat noch irgendetwas mit der Realität zu tun hat)?




> und was bedeutet das?
> was heißt Laufzeitdaten? wieso hängt das von irgendwas ab?
> wenn man das 10x ausführt, passiert 10x das gleiche, was genau soll in irgendeiner Form zu beachten sein?


Beide Methoden wählen einen unterschiedlichen Ansatz. Beide müssen Objekte erzeugen und Arrays kopieren, machen das jedoch auf unterschiedliche Weise.
Wie kannst du/ihr behaupten das der eine Ansatz dem anderen pauschal überlegen ist?
Wenn es wirklich so wäre, warum wandelt der SUN Compiler dann String + String in einen StringBuilder statt String.concat(String) um?
Die Art (und in diesem Fall Länge) der Daten ist entscheidend.


----------



## Saxony (22. Aug 2007)

Wildcard hat gesagt.:
			
		

> Wenn es wirklich so wäre, warum wandelt der SUN Compiler dann String + String in einen StringBuilder statt String.concat(String) um?



Naja weil StringBuilder die schnellste Variante darstellt um zwei Strings zu addieren - würde ich mal annehmen.

Nachdem ich das mit s = s.concat("a") verbessert habe, ergeben sich auch folgende Werte:


```
String + String (100k) : 24001
String.concat (100k) : 12094
StringBuilder (2M) : 94
StringBuffer (2M) : 141
```

Ich persönlich würde nun die Variante mit der kleinsten Ausführungszeit nehmen.
Und  - O Wunder - es deckt sich mit der von SUN gewählten.

bye Saxony


----------



## SlaterB (22. Aug 2007)

Wildcard hat gesagt.:
			
		

> > für deine Optimierungstheorien,
> > es zeigt sich doch sehr deutlich, dass absolut gar nix passiert
> 
> 
> Und diese Aussage triffst du pauschal für jeden Hotspot/JIT, ohne auch nur den Bytecode gesehen zu haben, oder die Optimierung ausgeschaltet zu haben (wobei dann wieder sehr fraglich ist, ob das Resultat noch irgendetwas mit der Realität zu tun hat)?


ich gehe nun mal von Tatsachen aus, 
ich behaupte ja gar nix, du behauptest, dass irgendwelche Optimierungen stattfinden, obwohl gar nix passiert




> Wie kannst du/ihr behaupten das der eine Ansatz dem anderen pauschal überlegen ist?


diese Aussage kann natürlich nur für die gegebenen Beispiele gelten 
und soll wie gesagt natürlich nicht für alle komischen HotSpot-Dinger dieser Welt gelten



> Die Art (und in diesem Fall Länge) der Daten ist entscheidend.


na warum sagst du das nicht gleich,
das ist natürlich ein interessanter Punkt, der bisher außen vor blieb,

allerdings wird zumindest bei mir mit höherer Länge der Vorsprung von concat() sogar noch größer..



> Wenn es wirklich so wäre, warum wandelt der SUN Compiler dann String + String in einen StringBuilder statt String.concat(String) um?


vieleicht ist es damit einfacher auch die ganzen ints und chars zu addieren?

nie würde jemand mit einem ein 10 Zeilen-Programm behaupten, dass Java alles falsch macht,
aber das tut der Aussage concat schneller als + keinen Abbruch
(gerne mit dem Zusatz: in den bisher betrachteten Regionen)


----------



## SlaterB (22. Aug 2007)

Saxony hat gesagt.:
			
		

> Wildcard hat gesagt.:
> 
> 
> 
> ...


ne gerade das stimmt ja nicht, + verwendet StringBuilder und ist damit sehr langsam,
hier mal ein Vergleichsprogramm mit langen Teilstrings:


```
public class StringTester
{
    static int k = 1800;
    static String append = "aaaaaaaaaaaaaaaaaaaaaaaaaaaa";

    public static void main(String[] args)
    {
        stringConcat();
        stringBuilderFast();
        stringBuilderSlow();
        stringPlus();

        stringConcat();
        stringBuilderFast();
        stringBuilderSlow();
        stringPlus();

        stringConcat();
        stringBuilderFast();
        stringBuilderSlow();
        stringPlus();
    }

    private static void stringPlus()
    {
        long timeStart = System.currentTimeMillis();
        String s = "";
        for (int i = k; i > 0; i--)
        {
            s += append;
        }
        System.out.println("String +     : " + (System.currentTimeMillis() - timeStart));
    }

    private static void stringBuilderFast()
    {
        long timeStart = System.currentTimeMillis();
        String s = "";
        for (int i = k; i > 0; i--)
        {
            StringBuilder b = new StringBuilder(s.length() + append.length());
            b.append(s);
            b.append(append);
            s = b.toString();
        }
        System.out.println("String b f   : " + (System.currentTimeMillis() - timeStart));
    }

    private static void stringBuilderSlow()
    {
        long timeStart = System.currentTimeMillis();
        String s = "";
        for (int i = k; i > 0; i--)
        {
            StringBuilder b = new StringBuilder();
            b.append(s);
            b.append(append);
            s = b.toString();
        }
        System.out.println("String b s   : " + (System.currentTimeMillis() - timeStart));
    }


    private static void stringConcat()
    {
        long timeStart = System.currentTimeMillis();

        String s = "";
        for (int i = k; i > 0; i--)
        {

            s = s.concat(append);
        }
        System.out.println("String.concat: " + (System.currentTimeMillis() - timeStart));
    }
}

Ausgabe:
String.concat: 172
String b f   : 500
String b s   : 1328
String +     : 1360
String.concat: 171
String b f   : 485
String b s   : 1359
String +     : 1375
String.concat: 188
String b f   : 500
String b s   : 1359
String +     : 1360
```
gilt natürlich nicht für HotSpot


----------



## Wildcard (22. Aug 2007)

Saxony hat gesagt.:
			
		

> Wildcard hat gesagt.:
> 
> 
> 
> ...



Und, O Wunder, String + String resultiert in einem StringBuilder. Wie deckt sich das mit deiner Aussage?  :roll: 

Verändern wir die Testdaten (die nach Slater's Meinung ja irrelevant sind):

```
public class StringTester
{
    static int k = 10000;

    public static void main(String[] args)
    {
        stringPlus();
        stringConcat();
        stringPlus();
        stringConcat();
        stringPlus();
        stringConcat();
        stringPlus();
        stringConcat();
    }

    private static void stringPlus()
    {
        long timeStart = System.currentTimeMillis();
        String s = "";
        for (int i = k; i > 0; i--)
        {
            s = s + k + k*2;
        }
        System.out.println("String +     : " + (System.currentTimeMillis() - timeStart));
    }

    private static void stringConcat()
    {
        long timeStart = System.currentTimeMillis();

        String s = "";
        for (int i = k; i > 0; i--)
        {

            s = s.concat(String.valueOf(k)).concat(String.valueOf(k*2));
            
        }
        System.out.println("String.concat: " + (System.currentTimeMillis() - timeStart));
    }
}
```

Wie sieht das Ergebnis jetzt aus?


```
String +     : 3156
String.concat: 3328
String +     : 3219
String.concat: 3109
String +     : 2610
String.concat: 2547
String +     : 2625
String.concat: 2547
```

Plötzlich sind beide gleich schnell.


> ich gehe nun mal von Tatsachen aus,
> ich behaupte ja gar nix, du behauptest, dass irgendwelche Optimierungen stattfinden, obwohl gar nix passiert



Wie du an den Werten sehen kannst, findet sehr wohl eine Optimierung statt.
Nach dem ersten Durchlauf müssen alle Klassen geladen sein, warum wird die Sache aber im zweiten Durchlauf nochmal schneller?



> aber das tut der Aussage concat schneller als + keinen Abbruch



Siehe Testdaten.


----------



## Wildcard (22. Aug 2007)

Noch ein interessantes Detail:
Verändert man 

```
s = s.concat(String.valueOf(k)).concat(String.valueOf(k*2));
```
zu

```
s = s.concat(String.valueOf(k)).concat(String.valueOf(k*2));
s = new String(s);
s = new String(s);
```
so sollte eine spürbare Verlangsamung eintreten. Plötzlich müssen wesentlich mehr Objekte erzeugt werden und die Strings sind gegen Ende der Schleife ja nicht gerade klein.
Es ändert sich aber *gar nichts*.
Warum? Es wird optimiert, daher kann man das alles in der Pfeife rauchen solange der Compiler, der JIT und der HopSpot Compiler daran rumbasteln.


----------



## Saxony (22. Aug 2007)

Hmm,

wenn String + String eh in einem StrinBuilder endet, wieso soll man dann überhaupt einen StringBuilder bei vielen Stringadditionen nehmen?

Oder anders gefragt wieso ist die Verwendung von StrinBuilder alleine wesentlich schneller als die Verwendung von String + String, wenn dieses sowieso wieder auf nen StringBuilder zurück fällt.?

bye Saxony


----------



## Wildcard (22. Aug 2007)

Saxony hat gesagt.:
			
		

> wenn String + String eh in einem StrinBuilder endet, wieso soll man dann überhaupt einen StringBuilder bei vielen Stringadditionen nehmen?
> 
> Oder anders gefragt wieso ist die Verwendung von StrinBuilder alleine wesentlich schneller als die Verwendung von String + String, wenn dieses sowieso wieder auf nen StringBuilder zurück fällt.?


Der Trick ist es, den StringBuilder an der richtigen Stelle, mit der richtigen Kapazität zu initialisieren.

Übrigens lassen sich die gewonnen Erkenntnisse auch sehr leicht umdrehen, wie dieser Test beweißt:



```
public class StringTester
{
    static int k = 10000;

    public static void main(String[] args)
    {
        stringPlus();
        stringConcat();
        stringPlus();
        stringConcat();
        stringPlus();
        stringConcat();
    }

    private static void stringPlus()
    {
        long timeStart = System.currentTimeMillis();
        String s = "";
        for (int i = k; i > 0; i--)
        {
            s = s + k + k*2 + k*3;
        }
        System.out.println("String +     : " + (System.currentTimeMillis() - timeStart));
    }

    private static void stringConcat()
    {
        long timeStart = System.currentTimeMillis();

        String s = "";
        for (int i = k; i > 0; i--)
        {

            s = s.concat(String.valueOf(k)).concat(String.valueOf(k*2)).concat(String.valueOf(k*3));
            
        }
        System.out.println("String.concat: " + (System.currentTimeMillis() - timeStart));
    }
}
```

Werte:


```
String +     : 6141
String.concat: 10593
String +     : 6407
String.concat: 10672
String +     : 5015   <-----optimierung
String.concat: 7281 <-----optimierung
```

Was lernen wir daraus?

1. Die Sache ist hochgradig Parameterabhängig
2. Mikrobenchmarks sind *nicht trivial* und generell wenig aussagekräftig.


----------



## SlaterB (22. Aug 2007)

pff, jetzt wirst du aber billig, das ist nicht dein Niveau..

dass concat() nur für Strings schneller ist stand von Anfang an fest,
habe ich ja auch vor dir geschrieben: 



			
				SlaterB hat gesagt.:
			
		

> > Wenn es wirklich so wäre, warum wandelt der SUN Compiler dann String + String in einen StringBuilder statt String.concat(String) um?
> 
> 
> vieleicht ist es damit einfacher auch die ganzen ints und chars zu addieren?



---------



			
				Wildcard hat gesagt.:
			
		

> Wie du an den Werten sehen kannst, findet sehr wohl eine Optimierung statt.
> Nach dem ersten Durchlauf müssen alle Klassen geladen sein, warum wird die Sache aber im zweiten Durchlauf nochmal schneller?


weil hier Strings gecached werden, was sich hier verständlicherweise auf beide Additonen gleich auswirkt,

was hat das mit dem vorherigen Programm zu tun?
habe ich behauptet, dass in allen Programmen der Welt nie etwas gecacht wird? 

was hat das mit dem Vergleich zwischen + und concat() zu tun?



> Es ändert sich aber gar nichts.
> Warum? Es wird optimiert, daher kann man das alles in der Pfeife rauchen solange der Compiler, der JIT und der HopSpot Compiler daran rumbasteln.


noch mal: behaupte ich dass das Wort Optimierung nicht im Lexikon steht?
dann hast du natürlich Recht..

aber wenn wir bei den Fakten bleiben, also 
String + String 
sowie 
String concat(String)
gegenüberstellen, dann ist concat schneller..


----------

aber einen neuen bisher nicht beachteten Umgebungsparameter hast du wieder aufgezeigt:
bei Hintereinanderausführung mehrerer Stringadditionen ist + bald schneller als concat:


```
public class StringTester
{
    static int k = 3800;
    static String append = "aaaa";

    public static void main(String[] args)
    {
        stringConcat();
        stringPlus();

        stringConcat();
        stringPlus();

        stringConcat();
        stringPlus();
    }

    private static void stringPlus()
    {
        long timeStart = System.currentTimeMillis();
        String s = "";
        for (int i = k; i > 0; i--)
        {
            s += append + append + append;
        }
        System.out.println("String +     : " + (System.currentTimeMillis() - timeStart));
    }

    private static void stringConcat()
    {
        long timeStart = System.currentTimeMillis();

        String s = "";
        for (int i = k; i > 0; i--)
        {

            s = s.concat(append).concat(append).concat(append);
        }
        System.out.println("String.concat: " + (System.currentTimeMillis() - timeStart));
    }
}

Ausgabe:
String.concat: 1313
String +     : 765
String.concat: 1094
String +     : 766
String.concat: 1094
String +     : 765
```

und sehr gerne stimme ich dir da zu, falls das an einer Optimierung liegt,
ich verschließe mich dem Wort Optimierung nicht auch wenn ich erkenne, dass in den frühenen Beispielen keine auftrat 

(edit: ach, liegt wohl nur daran, dass die kleinen Teilstrings zuerst zusammengefügt werden, nix optimiert  )

damit muss die Aussage weiter verfeinert werden:
concat schlägt sich umso besser, je weniger Additionen in einer Zuweisung stehen,
am besten bei genau einer

dass das nur für Strings gilt war von Anfang an klar,
je länger die Strings desto besser stehts für concat()



			
				Wildcard hat gesagt.:
			
		

> 1. Die Sache ist hochgradig Parameterabhängig


dem kann keiner wiedersprechen


			
				Wildcard hat gesagt.:
			
		

> 2. Mikrobenchmarks sind *nicht trivial* und generell wenig aussagekräftig.


was du gegen die Aussage hast verstehe ich aber nicht,
wahrscheinlich spielst du auf die Auswirkung in realen Programmen ab,
aber das ist ja immer ein sinnloses Unterfangen

der Test kann nur das aussagen, was er selber aussagt..,
wenn man tausendmal Wurzel aus 4 berechnet und sich wundert, dass im realen Leben tausendmal Wurzel aus 5 länger zu berechnen dauert,
dann ist man wirklich selber Schuld


----------



## Wildcard (22. Aug 2007)

SlaterB hat gesagt.:
			
		

> pff, jetzt wirst du aber billig, das ist nicht dein Niveau..
> 
> dass concat() nur für Strings schneller ist stand von Anfang an fest,
> habe ich ja auch vor dir geschrieben:


Was soll denn jetzt das bitte heißen?
Glaubst du String + irgendwas kann zaubern?
Die Konvertierung in einen String muss in beiden Fällen erfolgen, das tut nichts zur Sache.
Die Schleifenvariable zu verwenden war lediglich die einfachste Möglichkeit um den String Pool auszuhebeln, weil ich keine zufälligen char[]s erzeugen wollte.


----------



## SlaterB (22. Aug 2007)

ja, ich dachte, dass wäre der Grund, warum das + auf einmal so schnell ist wie das concat(),
aber das stimmte wohl gar nicht, hast Recht,

deine ganzen 'gleich schnell'-Beispiele sind nämlich nur deswegen gleichschnell weil du für + unfair abkürzt:

concat muss
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".concat("a").concat("a")
=
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".concat("a")
=
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
bewältigen,
während + den einfachen Weg
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+"a"+"a"
=
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"+"aa"
=
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
hat,


welch besseren Beweis gibt es für die Überlegenheit von concat(),
wenn es (in diesem Fall) selbst dann noch gleich schnell ist?


natürlich ist concat() nur im Kampf Mann gegen Mann schneller,
wenn man die Bedingungen also angleicht, sticht die Überlegenheit wieder deutlich hervor 


```
public class StringTester 
{ 
    static int k = 7000; 

    public static void main(String[] args) 
    { 
        stringPlus(); 
        stringConcat(); 
        stringPlus(); 
        stringConcat(); 
        stringPlus(); 
        stringConcat(); 
        stringPlus(); 
        stringConcat(); 
    } 

    private static void stringPlus() 
    { 
        long timeStart = System.currentTimeMillis(); 
        String s = ""; 
        for (int i = k; i > 0; i--) 
        { 
            s = s + k + k*2; 
        } 
        System.out.println("String +     : " + (System.currentTimeMillis() - timeStart)); 
    } 

    private static void stringConcat() 
    { 
        long timeStart = System.currentTimeMillis(); 

        String s = ""; 
        for (int i = k; i > 0; i--) 
        { 

            s = s.concat(String.valueOf(k).concat(String.valueOf(k*2))); 
            
        } 
        System.out.println("String.concat: " + (System.currentTimeMillis() - timeStart)); 
    } 
} 

Ausgabe:
String +     : 3125
String.concat: 1032
String +     : 3984
String.concat: 1016
String +     : 2390
String.concat: 1016
String +     : 2641
String.concat: 1000
```


----------



## Wildcard (22. Aug 2007)

Was erzählst du mir da für einen Unsinn?
Java ist, war und wird immer Linksassoziativ bleiben.  :roll: 
Du hast die Sache jetzt natürlich umgedreht, was bei der + Variante wegen den ints nicht möglich ist.
So kann man sich auch die Resultate besorgen die man sehen möchte. Du solltest Statistiker werden   :toll:


----------



## SlaterB (22. Aug 2007)

was genau ist daran jetzt Unsinn?

> was bei der + Variante wegen den ints nicht möglich ist.

benutzte doch String.valueOf()?


----------



## Wildcard (22. Aug 2007)

Das Ausdrücke *immer* von Links nach Rechts ausgewertet werden und nicht mal eben andersrum weil's gerade bequemer ist.


----------



## SlaterB (22. Aug 2007)

wie erklärst du dir 

```
public class StringTester
{
    static int k = 5000;

    public static void main(String[] args)
    {
        stringPlus1();
        stringPlus2();
        stringConcat();
        stringPlus1();
        stringPlus2();
        stringConcat();
        stringPlus1();
        stringPlus2();
        stringConcat();

    }

    private static void stringPlus1()
    {
        long timeStart = System.currentTimeMillis();
        String s = "";
        for (int i = k; i > 0; i--)
        {
            s = k + s + k * 2;
        }
        System.out.println("String +1    : " + (System.currentTimeMillis() - timeStart));
    }

    private static void stringPlus2()
    {
        long timeStart = System.currentTimeMillis();
        String s = "";
        for (int i = k; i > 0; i--)
        {
            s = s + k + k * 2;
        }
        System.out.println("String +2    : " + (System.currentTimeMillis() - timeStart));
    }

    private static void stringConcat()
    {
        long timeStart = System.currentTimeMillis();

        String s = "";
        for (int i = k; i > 0; i--)
        {

            s = s.concat(String.valueOf(k).concat(String.valueOf(k * 2)));

        }
        System.out.println("String.concat: " + (System.currentTimeMillis() - timeStart));
    }
}

Ausgabe:
String +1    : 2922
String +2    : 1172
String.concat: 406
String +1    : 2813
String +2    : 1156
String.concat: 375
String +1    : 2797
String +2    : 1156
String.concat: 375
```
?


----------



## Wildcard (22. Aug 2007)

Was möchtest du mir damit schon wieder sagen?
Jetzt verwendest du 3 verschiedene Reihenfolgen um die Strings zusammen zu bauen und 2 verschiedene Methoden.
Welchen der 3 Fälle soll ich dir erklären?


----------



## SlaterB (22. Aug 2007)

ich behaupte, dass die Methode
s + k + k * 2
nur deshalb so schnell ist, weil k + k * 2 zuerst zusammengefügt werden


du sagst, dass 'Ausdrücke immer von Links nach Rechts ausgewertet',
also (s + k) + k * 2

dann wundert mich, warum 
s = k + s + k * 2; 
so viel langsamer ist

concat war in diesem Beispiel nicht von Belang


----------



## Wildcard (22. Aug 2007)

Du schaffst mich...
Du bemerkst selbst, dass concat auf einmal schneller wird, wenn man die Reihenfolge vorteilhafter gestalltet und wunderst dich dann ernsthaft wenn der gleiche Effekt auch bei String + String auftritt?  :lol: 

Wenn du der Spezifikation (die eindeutig von Linksassoziativität spricht) nicht glaubst, dann nimm die Sache selbst in die Hand und setz Klammern:

```
s = (s + k) + k*2;
```
Du wirst sehen, das die Werte davon unbeindruckt sind.
Bei deiner concat Lösung hingegen verwendest du s+(k+k*2), was effizienter ist, sich bei ints aber nicht analog übertragen lässt.
Du vergleichst Äpfel mit Birnen, was soll ich dazu noch sagen.


----------



## SlaterB (22. Aug 2007)

Wildcard hat gesagt.:
			
		

> Du bemerkst selbst, dass concat auf einmal schneller wird, wenn man die Reihenfolge vorteilhafter gestalltet und wunderst dich dann ernsthaft wenn der gleiche Effekt auch bei String + String auftritt?  :lol:


hmm? für mich siehst eher so aus:
du hattest mit der vorteilhaften Reihenfolge für + angefangen, und das genutzt um zu sagen, dass + nun gleichschnell wie concat ist,

aber das war unfair, denn concat hatt da nicht die vorteilhafte Reihenfolge genutzt,

nun setze ich auch für concat die vorteilhafte Reihenfolge, was concat promt wieder einen Riesenvorsprung verschafft

wo in dieser Abfolge 'wundere' ich mich?
ich habe den Effekt bei + erkannt und ihn dann auf concat übernommen





> Wenn du der Spezifikation (die eindeutig von Linksassoziativität spricht) nicht glaubst, dann nimm die Sache selbst in die Hand und setz Klammern:
> 
> ```
> s = (s + k) + k*2;
> ...



was genau ist denn da jetzt die Aussage, dass + trotz anderer Klammerung genauso schnell ist?
nun, das mag so sein, ich weiß nicht, wie es intern abläuft,

selbst wenn nun also + auch bei schlechter Klammerung optimal abgearbeitet wird,
bedeutet es doch immer noch, dass zumindest ein geschickt geklammerter concat()-Ausdruck immer (bzw. nur unter den bisher betrachteten Beispielen) schneller ist als ein beliebig geklammerter +-Ausdruck, oder?



> Du vergleichst Äpfel mit Birnen, was soll ich dazu noch sagen.


was genau meinst du damit?


----------



## Wildcard (22. Aug 2007)

Nein, du gehst immer noch davon aus, das in genanntem Beispiel String + String erst die beiden kurzen Strings verknüpft und zum Schluß den langen. Das ist aber falsch, da von links nach rechts gearbeitet wird, also erst lang + kurz und dann + kurz.
Denn unfairen Vorteil den du zu erkennen meintest, hast du selbst erst geschaffen, und zwar auf der concat Seite.


----------



## SlaterB (22. Aug 2007)

> Nein, du gehst immer noch davon aus, das in genanntem Beispiel String + String erst die beiden kurzen Strings verknüpft und zum Schluß den langen. Das ist aber falsch, da von links nach rechts gearbeitet wird, also erst lang + kurz und dann + kurz.


was macht das für einen Unterschied, wenn doch letztlich das Ergebnis genau so lange dauert als wenn es so wäre?
ich weiß nicht, wie es intern optimiert wird,
aber es kommt genau die Zeit raus, als wenn erst die beiden kurzen addiert werden,

das Ergebnis stimmt also, der Weg dahin ist doch egal?

und wenn wirklich lang + kurz + kurz in der Reihenfolge (lang + kurz) + kurz ausgewertet wird,
warum ist dann kurz + lang + kurz so viel langsamer?


------------


hmm, also noch mal von vorne, du hattest irgendwann ein erstes Beispiel gepostet,
ich will nicht alles wiederholen, nur zwei Sätze von dir zum Ergebnis

> Wie sieht das Ergebnis jetzt aus? 
[..]
> Plötzlich sind beide gleich schnell. 

dieses Beispiel fechte ich nun an, ich denke, dass da das + nur deshalb so schnell ist,
weil da irgendwas intern besser läuft,

so, und diesen Vorteil kann man concat() auch verschaffen, oder nicht?,
concat ist dann wieder wahnsinnig schneller


```
public class StringTester
{
    static int k = 7000;

    public static void main(String[] args)
    {
        stringPlusFast();
        stringConcatFast();

        stringPlusSlow();
        stringConcatSlow();

        stringPlusFast();
        stringConcatFast();

        stringPlusSlow();
        stringConcatSlow();

    }

    private static void stringPlusFast()
    {
        long timeStart = System.currentTimeMillis();
        String s = "";
        for (int i = k; i > 0; i--)
        {
            s = s + k + k * 2;
        }
        System.out.println("\nString +      fast: " + (System.currentTimeMillis() - timeStart));
    }

    private static void stringPlusSlow()
    {
        long timeStart = System.currentTimeMillis();
        String s = "";
        for (int i = k; i > 0; i--)
        {
            s = s + k;
            s = s + k * 2;
        }
        System.out.println("\nString +      slow: " + (System.currentTimeMillis() - timeStart));
    }

    private static void stringConcatFast()
    {
        long timeStart = System.currentTimeMillis();

        String s = "";
        for (int i = k; i > 0; i--)
        {
            s = s.concat(String.valueOf(k).concat(String.valueOf(k * 2)));
        }
        System.out.println("String.concat fast: " + (System.currentTimeMillis() - timeStart));
    }


    private static void stringConcatSlow()
    {
        long timeStart = System.currentTimeMillis();

        String s = "";
        for (int i = k; i > 0; i--)
        {
            s = s.concat(String.valueOf(k)).concat(String.valueOf(k * 2));
        }
        System.out.println("String.concat slow: " + (System.currentTimeMillis() - timeStart));
    }
}

Ausgabe:

String +      fast: 3219
String.concat fast: 1047

String +      slow: 6250
String.concat slow: 2984

String +      fast: 2688
String.concat fast: 1078

String +      slow: 4875
String.concat slow: 2875
```

+ fast ist hier viel schneller als + slow, weil alles in einer Zeile steht (ob wegen Reihenfolge oder was anderem ist letztlich ja egal),

+ fast ist nun genauso schnell wie Concat slow,
aber bei Concat kann man noch optimieren, während + schon in seiner fast-Version ist,
Concat fast ist wieder deutlich schneller als + fast!


----------



## Wildcard (22. Aug 2007)

SlaterB hat gesagt.:
			
		

> und wenn wirklich lang + kurz + kurz in der Reihenfolge (lang + kurz) + kurz ausgewertet wird,
> warum ist dann kurz + lang + kurz so viel langsamer?


Zunächst mal solltest du das 'wirklich' weglassen, oder mich vom Gegenteil überzeugen (was dir sehr schwer fallen wird).
Der Grund hängt mit den Internas des Builders zusammen.
Zur Laufzeit wird String + String in dieser Art abgearbeitet:

```
new StringBuilder(s).append(k).append(k*2);
```
Er wird mit einem Overhead von 16 Zeichen erzeugt, kann also im günstigen Fall die anderen Strings appenden ohne ein neues Array anlegen und kopieren zu müssen.
Wenn jetzt allerdings der kleine String k am Anfang übergeben wird, ist der Buffer wesentlich kleiner und es muss in jedem Fall kopiert werden. Das macht einen riesen Unterschied.
Du wirst übrigens feststellen, dass die Reihenfolge die du für dein concatFast verwendest mit einem StringBuilder auf identische Ergebnisse kommt:

```
s = new StringBuilder(s).append(new StringBuilder(k).append(k*2).toString()).toString();
```
Das ganze lässt sich nur nicht 1:1 auf die String + String Variante übertragen, da bei s + (k+k*2) die Klammer als int aufgelöst wird.
Also sei bitte so gut und lass die Reihenfolge ruhen, das ist nicht das schlagende Argument auf das du hoffst und in der Praxis sowieso völlig irrelevant :wink:




> das Ergebnis stimmt also, der Weg dahin ist doch egal?


Das ist jetzt einfach nur Blauäugig.



> dieses Beispiel fechte ich nun an, ich denke, dass da das + nur deshalb so schnell ist,
> weil da irgendwas intern besser läuft,


Was läuft denn da deiner Meinung nach 'intern besser'?



> so, und diesen Vorteil kann man concat() auch verschaffen, oder nicht?


Welchen Vorteil? Du vermutest nur irgendeine dubiose höhere Macht und versuchst nun durch Veränderung des Algorithmus zu retten was von deinen Anfangsbehauptungen noch geblieben ist.

Es geht immer nur darum wie viele Arrays erzeugt werden müssen und wie oft umkopiert werden muss.
Man kann nahezu beliebig viele verschiedene Fälle produzieren und je nach Fall wird entweder concat oder String + String schneller sein.

Wenn dir jetzt hoffentlich klar ist, dass man Pauschalaussagen (wie du sie getätigt hast) nicht treffen kann und am besten ganz die Finger von Mikrobenchmarks lässt, können wir das Thema gerne beenden.


----------



## SlaterB (22. Aug 2007)

ah, nun ist ja endlich geklärt, wie die Strings von links aus zusammengeführt werden,
kannst du mir Langsamdenker auch ruhig gleich verraten,
ich gelobe, die Rechtsauswertung zumindest in diesem Thread nicht mehr zu erwähnen 

-----

an meiner Aussage 'wie es dazu kommt, ist egal' darf ich aber festhalten, 
denn immer noch gilt: + ist dem Beispiel nur einigermaßen konkurrenzfähig,
weil es eine bestimmte Situation ausnutzt, nämlich zwei kurze Strings dahinter,
(wenn diese Strings aber länger als 16 sind, dann Gnade Gott  )

genau auf die gleiche Weise, durch Ausnutzung der Kürze der angefügten Strings, kann man auch concat() optimieren,
was ist daran falsch?


> Welchen Vorteil? Du vermutest nur irgendeine dubiose höhere Macht und versuchst nun durch Veränderung des Algorithmus zu retten was von deinen Anfangsbehauptungen noch geblieben ist.


du hast + doch auch durch Veränderung des Algorithmus schneller gemacht?



> Man kann nahezu beliebig viele verschiedene Fälle produzieren und je nach Fall wird entweder concat oder String + String schneller sein.


ha, kommen wir also zur Kernaussage:
1.
im Kampf Mann gegen Mann,
also 
String stringA = stringB + stringC;
vs
String stringA = stringB.concat(stringC);

ist concat() (bisher  ) in ALLEN DENKBAREN Varianten uneinholbar schneller,
wenn dir dieser wichtige Anwendungsfall nichts bedeutet, na dann kann ich dir auch nicht helfen 

2.
in BELIEBIGEN Situationen ist a.) concat() in der der Mehrzahl der Möglichkeiten ganz automatisch besser
(etwas subjektiv, welche Situationen man als normal ansieht)
+
b.) concat() kann durch simple Optimierung (richige Klammerung) IMMER schneller als + sein 
(wiederum nur für die bisher bekannten Beispiele, wobei man in dem Fall eh zum StringBuilder wechseln würde)

wenn diese beiden Punkte keine durchschlagenden Argumente für die Überlegenheit sind, was dann?


edit: lass es mich nochmal wiederholen: 
wenn man bei mehr als 2 String eh hoffentlich einen Stringbuilder einsetzt, 
dann bleibt ja eigentlich nur noch 1., und in diesem Fall ist concat() bisher immer besser als + ....


----------



## Wildcard (22. Aug 2007)

:autsch: 


> an meiner Aussage 'wie es dazu kommt, ist egal' darf ich aber festhalten,
> denn immer noch gilt: + ist dem Beispiel nur einigermaßen konkurrenzfähig,
> weil es eine bestimmte Situation ausnutzt, nämlich zwei kurze Strings dahinter,
> (wenn diese Strings aber länger als 16 sind, dann Gnade Gott icon_wink.gif )



Um Gottes willen, nein.
Es werden keine 'bestimmten Situationen' ausgenutzt.
Wir haben nur einen sehr speziellen Fall betrachtet.
Näheres dazu später.



> du hast + doch auch durch Veränderung des Algorithmus schneller gemacht?


Nein, ich habe die Daten geändert, da (wie wiederholt betont) die Daten entscheidend für die Performance sind.


> ist concat() (bisher :wink in ALLEN DENKBAREN Varianten uneinholbar schneller,
> wenn dir dieser wichtige Anwendungsfall nichts bedeutet, na dann kann ich dir auch nicht helfen


Das ist grundfalsch.



> in BELIEBIGEN Situationen ist a.) concat() in der der Mehrzahl der Möglichkeiten ganz automatisch besser
> (etwas subjektiv, welche Situationen man als normal ansieht)


Das gleiche wie oben und immernoch falsch


> concat() kann durch simple Optimierung (richige Klammerung) IMMER schneller als + sein
> (wiederum nur für die bisher bekannten Beispiele, wobei man in dem Fall eh zum StringBuilder wechseln würde)


Ich dachte du wolltest das nicht mehr erwähnen. Das hat weder Gehalt, noch Bewandtnis. In der Realität würdest du weder concat noch + in einer Schleife einsetzen. Wenn doch, dann ist dir in der Regel nicht klar welcher String wie lang ist und wie am besten geklammert wird.



> wenn diese beiden Punkte keine durchschlagenden Argumente für die Überlegenheit sind, was dann?


Du hast gar keine Argumente, weil dir nicht klar zu sein scheint wie die Sache funktioniert.

Wie funktioniert concat?
Ein neues Array der Länge String1+String2 wird allokiert und die Werte kopiert.

Wie funktioniert String + String?
Ein StringBuilder wird erzeugt der initial den ersten String aufnimmt + 16 Zeichen overhead.
Wenn das nicht ausreicht wird eine minimale Größe sichergestellt die alle Zeichen aufnehmen kann, in der regel aber *verdoppelt*.
Der StringBuilder wird also größer und größer und muss bei längeren Strings  immer weniger Arbeit leisten.
Bei concat wird der Aufwand aber immer größer weil mehr kopiert werden muss.

Du merkst wohin das führt?
Es hängt davon ab, welche Daten verwendet werden, ab wann sich der Overhead des StringBuilder rechnet und er deutlich schneller wird.

Du kannst jetzt weiter Pseudodaten rumschubsen und dich freuen das du viel cleverer bist als die Leute von SUN, die den StringBuilder statt concat verwendet, oder du wachst auf und kommst auf die Idee, das große Strings das größere Performanceproblem darstellen und der StringBuilder daher absolut Sinn macht weil er besser _skaliert_.  :autsch: 

Du bist nun auch schon länger dabei, aber das du dich so hartnäckig dagegen sträubst, dass man die Sache nicht einfach in Schwarz und Weiß aufteilen kann überrascht mich doch sehr.




> wenn man bei mehr als 2 String eh hoffentlich einen Stringbuilder einsetzt,



Auch das ist so nicht richtig.

Das ist nicht das entscheidende Kriterium. Entscheidend ist, ob die Codestelle innerhalb einer Schleife oder Rekursion aufgerufen wird. Dann muss nämlich der StringBuilder her (und zwar aussen). Ob das nun 2,3,4 oder 300 Strings im Code sind, ist unerheblich.


So... Fußball jetzt  :autsch:


----------



## SlaterB (22. Aug 2007)

Wildcard hat gesagt.:
			
		

> Um Gottes willen, nein.
> Es werden keine 'bestimmten Situationen' ausgenutzt.
> Wir haben nur einen sehr speziellen Fall betrachtet.
> Näheres dazu später.


schade dass nichts kam



> > du hast + doch auch durch Veränderung des Algorithmus schneller gemacht?
> 
> 
> Nein, ich habe die Daten geändert, da (wie wiederholt betont) die Daten entscheidend für die Performance sind.


du hast 
s1 = s1 +s2;
s1 = s1 + s3;
in
s1 = s1 + s2 + s3;
optimiert, wo ist da eine Datenänderung? 






> Das ist grundfalsch.





> Das gleiche wie oben und immernoch falsch


schade, alles ohne Begründung



> > concat() kann durch simple Optimierung (richige Klammerung) IMMER schneller als + sein
> > (wiederum nur für die bisher bekannten Beispiele, wobei man in dem Fall eh zum StringBuilder wechseln würde)
> 
> 
> Ich dachte du wolltest das nicht mehr erwähnen. Das hat weder Gehalt, noch Bewandtnis. In der Realität würdest du weder concat noch + in einer Schleife einsetzen. Wenn doch, dann ist dir in der Regel nicht klar welcher String wie lang ist und wie am besten geklammert wird.


ich wollte die Rechts- statt Linksauswertung nicht mehr erwähnen,
dass man concat() richtig anordnen kann widerspricht dem nicht,

über die Reihenfolge muss man im ganzen Leben nur einmal nachdenken:
public static String concatIntelligent(String... strings);





> Wie funktioniert concat?
> [..]


falls da irgendwas zum Thema drin ist, dann musst du das für mich leider nochmal verständlich formulieren,
für mich liest sich das so, als wenn du concat() mit StringBuider vergleichst, das erübrigt sich..




> Du kannst jetzt weiter Pseudodaten rumschubsen und dich freuen das du viel cleverer bist als die Leute von SUN, die den StringBuilder statt concat verwendet, oder du wachst auf und kommst auf die Idee, das große Strings das größere Performanceproblem darstellen und der StringBuilder daher absolut Sinn macht weil er besser _skaliert_.  :autsch:


an welcher Stelle habe ich das bisher behauptet oder einen Austausch vorgeschlagen?
die werden sich was dabei gedacht haben, dessen bin ich mir sicher




> Du bist nun auch schon länger dabei, aber das du dich so hartnäckig dagegen sträubst, dass man die Sache nicht einfach in Schwarz und Weiß aufteilen kann überrascht mich doch sehr.


warum muss denn ein schwarzes Bild auch weiße Anteile enthalten?
ich halte mich immer an die vorliegenden Fakten, ich sage doch nur wie es sich bisher für mich darstellt,
von alleine kommst du ja nicht dazu, die richtige Sichtweise darzustellen 

ich kann mir dabei gut vorstellen dass es weiteres zu bedenken gibt, kein Problem dann mein Bild zu erweitern,

z.B. mit der StringBuilder-Verdoppelung,
damit kann ich mein Argument 2.b) 'concat kann IMMER besser als + gemacht werden' so nicht mehr stehenlassen,
bei der Addition von mehreren etwa gleich großen Strings wirkt sich der Vorteil des StringBuilders aus,
während concat() jedes mal eine neues Array erstellen muss,
kein Problem für mich dies einzubauen,

man muss natürlich wieder sagen, dass das eine Spezialsituation ist, die eigentlich sowieso in den Bereich der expliziten Verwendung eines StringBuilders fällt,



2.b. muss also von 'IMMER' auf 'meistens' abgeschwächt werden, was freilich wie 2.a. von Anfang an subjektiv ist,
und sowieo eher theoretisch, weil man dann meistens mit StringBuilder besser dran ist,

1. scheint mir weiterhin felsenfest, wobei ich nicht wetten würde, dass dagegen nichts sprechen kann,

ich verstehe deine Taktik nicht, warum sagst du zigmal 'das ist irrsinng', statt Schritt für Schritt die Argumente aufzuzählen,
dann ginge das viel schneller voran..


----------



## Wildcard (22. Aug 2007)

Welche Argumente denn?
Du kaust immer wieder Dinge durch die wir schon hatten.


> ich halte mich immer an die vorliegenden Fakten,
> ....
> ich verstehe deine Taktik nicht, warum sagst du zigmal 'das ist irrsinng', statt Schritt für Schritt die Argumente aufzuzählen,
> dann ginge das viel schneller voran..


Gute Idee.

Also zu den harten Fakten ohne auf die Implementierung von concat und StringBuilder einzugehen:

Es wurden mit wenigen schwachsinnigen Tests 3 Fälle festgestellt:
1. concat schneller als String + String
2. concat und String + String gleich schnell
3. String + String schneller als concat

Genau das versuche ich seit 3 Seiten Diskussion begreiflich zu machen.


----------



## SlaterB (22. Aug 2007)

tja, wenn du es nicht korrigieren willst (falls es falsch ist),
dann bleibe ich also dabei, vorallem bei

String stringA = stringB + stringC;
(langsamer)
vs
String stringA = stringB.concat(stringC); 
(schneller)

ich kann mir nämlich bisher nicht vorstellen, wie es mal andersrum laufen würde,
falls du es weißt, so verrate es bitte


----------



## Wildcard (22. Aug 2007)

Du redest jetzt vom einfachsten Fall einer String Zuweisung s = s1 + s2 bzw. s = s1.concat(s2) ohne das weitere Dinge mit dem String passieren?
Ja, in diesem Fall wird concat schneller sein.
StringBuilder muss folgende Dinge erledigen:
1. Array allokieren und mit s1 befüllen
2. s2 ins Array übertragen und gegebenfalls ein neues, größeres Array erzeugen
3. ein array mit der Länge des Gesamtstrings erzeugen und mit s1 und s2 befüllen

Bei concat sieht's folgendermaßen aus:
1. Array der Größe s1 + s2 allokieren
2. Array mit s1 und s2 befüllen

Es fällt also ein Schritt weg.

Sobald die Sache komplizierter wird (sprich real), sieht's dann auch schon wieder anders aus  :wink:


----------



## SlaterB (22. Aug 2007)

schön, dass das abgehakt ist,
du magst zu 'Sobald die Sache komplizierter wird' überlenken,
für mich ist String + String aber 90% der Wichtigkeit, der einzig richtig sinnvolle Einsatz

bei mehreren Strings ist einem im Grunde entweder die Performance egal (sie spielt keine Rolle, z.B. in Debug-Ausgaben)
oder man verwendet einen StringBuilder

wenn man sich dennoch auf das Gedankenspiel einlässt, dann kommen wir zu 2.a. und 2.b.
da können wir nicht mehr viel diskutieren, denke ich,

ich sehe da die Möglichkeiten von concat() deutlich im Vorteil,

z.B. bei den bisher in dem Thread verwendeten Beispielen
'großen String mit kleinen Strings auffüllen' ist concat besser,
muss natürlich intelligent eingesetzt werden, das kann man ja wohl erwarten,

und  wenn man mehr als 16 Chars hinzufügt siehst für + oft sehr übel aus,

die Spezialsituation 'viele gleichgroße String in einer Code-Zeile (!) zusammenzuaddieren',
die den StringBuilder bevorteilt, halte ich dagegen für deutlich schwächer,
aber das ist vollkommen subjektiv


----------



## Wildcard (22. Aug 2007)

SlaterB hat gesagt.:
			
		

> für mich ist String + String aber 90% der Wichtigkeit, der einzig richtig sinnvolle Einsatz


Ich sehe dafür überhaupt keinen sinnvollen Einsatz. Gar keinen.
Wenn es sich nicht um eine kritische Stelle handelt mach ich String + String weil's einfacher und völlig egal ist, an kritischen Stellen nehme ich die Sache selbst mit Arrays, ByteBuffern oder StringBuildern in die Hand.


----------



## SlaterB (22. Aug 2007)

aber wozu, wenn concat besser ist?
da kann ich ja mal deine Argumentationsweise verwenden:
warum haben die Sun-Leute concat intern das char-Array gegeben und keinen StringBuilder?  


dass + und concat generell nicht so wichtig sind, ändert ja nichts an dem Ergebnis, dass concat besser ist, oder?
(besser vor allem beim dualen String + String)

und sag jetzt nicht, dass nur String + String unwichtig ist, + mit mehreren Teilstrings aber wieder wichtiger


----------



## Wildcard (23. Aug 2007)

Wozu? Weil es lesbarer ist und mir eine millisekunde mehr oder weniger gelinde gesagt am Ar*** vorbei geht.
Oder willst du mir jetzt erzählen du nimmst diese 'Resultate' als Anlass dafür an unkritischen Stellen das '+' durch concat zu ersetzen?  :shock:


----------



## SlaterB (23. Aug 2007)

// doppelt


----------



## SlaterB (23. Aug 2007)

bin ich verrückt?  :bae: 

es geht von Anfang an nur um die Aussage 'concat ist [ich wiederhole nicht die besprochenen Parameter] schneller als +'

du bist derjenige, der dagegen anredet 

edit:
meine Frage 'Wozu?' bezog sich auf deinen Satz
>  an kritischen Stellen nehme ich die Sache selbst mit Arrays, ByteBuffern oder StringBuildern in die Hand.
was nicht schneller als concat sein kann und gewiss nicht lesbarer
(in der Situation nur String + String, darum ging es da ja gerade)


----------



## Wildcard (23. Aug 2007)

SlaterB hat gesagt.:
			
		

> meine Frage 'Wozu?' bezog sich auf deinen Satz
> >  an kritischen Stellen nehme ich die Sache selbst mit Arrays, ByteBuffern oder StringBuildern in die Hand.
> was nicht schneller als concat sein kann und gewiss nicht lesbarer
> (in der Situation nur String + String, darum ging es da ja gerade)


Wie bitte?
Es ist sogar extrem viel schneller.  :shock: 
Hier deinen Tester etwas vereinfacht wie man es richtig machen würde (und das ist der einzig interessante Fall):

```
public class StringTester
{
    static int k = 50000;

    public static void main(String[] args)
    {
        stringPlus1();
        stringConcat();
        stringPlus1();
        stringConcat();
        stringPlus1();
        stringConcat();

    }

    private static void stringPlus1()
    {
        long timeStart = System.currentTimeMillis();
        StringBuilder b = new StringBuilder();
        for (int i = k; i > 0; i--)
        {
            b.append(k);
        }
        String s = b.toString();
        System.out.println("String +1    : " + (System.currentTimeMillis() - timeStart));
    }


    private static void stringConcat()
    {
        long timeStart = System.currentTimeMillis();

        String s = "";
        for (int i = k; i > 0; i--)
        {

            s = s.concat(String.valueOf(k));

        }
        System.out.println("String.concat: " + (System.currentTimeMillis() - timeStart));
    }
}
```

Sieht dann so aus:

```
String +1    : 15
String.concat: 25735
String +1    : 15
String.concat: 25610
String +1    : 15
```


----------



## SlaterB (23. Aug 2007)

..
soll mir das jetzt neu sein oder wie? 

also nochmal für dich nachgerückt

ich sagte 
"für mich ist String + String aber 90% der Wichtigkeit, der einzig richtig sinnvolle Einsatz"
es geht also nur um 
String stringA = stringB + stringC; 

darauf sagst du 
"Ich sehe dafür überhaupt keinen sinnvollen Einsatz. Gar keinen.
Wenn es sich nicht um eine kritische Stelle handelt mach ich String + String weil's einfacher und völlig egal ist, an kritischen Stellen nehme ich die Sache selbst mit Arrays, ByteBuffern oder StringBuildern in die Hand."

das habe ich interpretiert als 
"an kritischen Stellen [für String stringA = stringB + stringC;] nehme ich die Sache selbst mit Arrays, ByteBuffern oder StringBuildern in die Hand."
und fragte "Wozu?"

du meintest offensichtlich was anderes, ist ja nicht schlimm,
aber dass ich nun concat() statt StringBuilder vorschlage ist ja eine gewagte Folgerung


----------



## Wildcard (23. Aug 2007)

Ja, ganz offensichtlich reden wir aneinander vorbei.

Für mich gibt es zu keiner Zeit eine Notwendigkeit concat aufzurufen. Jede Stelle bei der String + String steht ist so unkritisch, das es keine Rolle spielt.


----------



## SlaterB (23. Aug 2007)

dem stimme ich zu, benutze ich auch nie,

dennoch werde ich hier nicht von 'concat besser als +' abrücken, ätsch 
(nur aus Geschwindigkeitssicht, natürlich nicht schön im Code usw)


----------



## masta // thomas (23. Aug 2007)

Mh.. könnte einer von euch lieben ein kurzes Résumé schreiben? Eigentlich möchte ich nur wissen - StringBuilder oder StringBuffer?


----------



## SlaterB (23. Aug 2007)

> Eigentlich möchte ich nur wissen 

hattest du die Frage hier schonmal gestellt oder wie? 

bei StringBuilder und Buffer gibts oberflächlich gesehen nicht viel zu nennen, 
Buffer ist synchronized, also Thread-sicher und dafür bisschen langsamer,

wie viel, das kannst du in kleinen Testprogrammen testen, auch wenn Wildcard dich hauen würde 
oder siehe Beispiele von Saxony auf der ersten Seite,
ist aber vergleichsweise irrelevant, ein kleines bisschen eben,

wenn du beim Programmieren bei 'StringBu' bist und weißt, dass nicht mehrere Threads gleichzeitig kommen werden, 
dann sollten deine nächsten Buchstaben 'ilder' sein statt 'ffer', und schon sparst du ein paar unwesentliche Millisekunden,
mehr kann man dazu kaum sagen


----------



## masta // thomas (23. Aug 2007)

Das ist genau so eine Antwort, die ich erwartet habe  super, danke SlaterB!

(Die Frage hab ich nicht schonmal gestellt  aber vor lauter heissen Diskussionen hab ich irgendwann die Pointe überlesen / vergessen )


----------



## Saxony (23. Aug 2007)

Hiho,

naja da sind wir nun durch oder wie?

Mit dem Fazit:

StringA = StringB + StringA
ist langsamer als
StringA = StringA.concat(StringB)

und das alles ist noch langsamer als
StringBuffer
bzw.
StringBuilder

Weil falls das später mal jemand lesen sollte, will der nach 4 Seiten Diskussion auch mal ne Zusammenfassung sehen. 

Zudem würde mich mal interessieren wie so eine Diskussion im Biergarten verlaufen wäre. Mit etwas Glück vielleicht auch ohne Handgreiflichkeiten! 

Jaja Performance ist ein hartes Brot!!! 

[edit]
Das nächste mal müssen wir mal vorher in einem Pflichtenheft festlegen worum es geht!
[/edit]

bye Saxony


----------



## SlaterB (23. Aug 2007)

zum Vergleich von + und concat nochmal:
es gibt noch einen wichtigen Fall (sofern man beim dem Thema überhaupt von wichtig sprechen kann), 
in dem + überlegen ist:

bei der einfachen Addition mehrerer Strings, ohne einen großen Gesamtstring aufzubauen,
werden dabei mehr als 16 Zeichen zusammengefügt, sinkt der Vorteil von +, ist aber immer noch da,
concat kann in dem kleinen Bereich auch kaum durch Klammerung punkten, es sind eben n-1 einzelne Array-Erstellungen für n Teilstrings:


```
public class StringTester
{
    static int k = 9000000;
    static String st;

    public static void main(String[] args)
    {
        st = "12";

        stringPlus();
        stringConcat();
        stringConcat2();

        stringPlus();
        stringConcat();
        stringConcat2();

        st = "1234";

        stringPlus();
        stringConcat();
        stringConcat2();

        stringPlus();
        stringConcat();
        stringConcat2();

    }

    private static void stringPlus()
    {
        long timeStart = System.currentTimeMillis();
        String s = "";
        for (int i = k; i > 0; i--)
        {
            s = st + st + st + st + st + st;
        }
        System.out.println("\nString +      : " + (System.currentTimeMillis() - timeStart));
    }

    private static void stringConcat()
    {
        long timeStart = System.currentTimeMillis();

        String s = "";
        for (int i = k; i > 0; i--)
        {
            s = st.concat(st).concat(st).concat(st).concat(st).concat(st);
        }
        System.out.println("String.concat : " + (System.currentTimeMillis() - timeStart));
    }

    private static void stringConcat2()
    {
        long timeStart = System.currentTimeMillis();

        String s = "";
        for (int i = k; i > 0; i--)
        {
            s = st.concat(st).concat(st.concat(st)).concat(st.concat(st));
        }
        System.out.println("String.concat2: " + (System.currentTimeMillis() - timeStart));
    }
}

Ausgabe:


String +      : 3766
String.concat : 5673
String.concat2: 5516

String +      : 3735
String.concat : 5485
String.concat2: 5204

// ab hier > 16 Chars, schlechter für +

String +      : 4689
String.concat : 6001
String.concat2: 5516

String +      : 4688
String.concat : 5939
String.concat2: 5532
```

concat bleibt bei 2 Strings vorne,

im Bereich mehrerer Strings siehts für + aber nun deutlich besser aus,
ich sehe dort nun + in Führung, denn das hier angegebene Beispiel ist ja wirklich ein vergleichsweise wichtiges Feld

bei exotischen Situationen mit sehr großen Strings wäre concat() wieder besser (subjektiv)


----------

