# Programmier-Stil : Speicher vs. Quellcode



## hdi (24. Feb 2009)

Hey,

ich habe in der Uni gelernt, dass es wichtiger ist, sauberen und klar lesbaren
Quellcode zu schreiben, auch wenn es effizienter gehen könnte.
(Ausnahme irgendwelche krassen Algorithmen natürlich)

Das finde ich eig. auch ganz gut.

Ich bin jetzt seit 1 Monat Werkstudent und arbeite an einer Web-App mit.
Heute hat sich mein Chef den von mir geschrieben Code angesehen, und ihn 
komplett umgeschrieben. Was er da gemacht hat war meiner Meinung nach nich so geil.

Das Ding ist, dass ich mir bestimmte Referenzen in einer Methode geholt habe,
weil ich einige verwenden musste. Insgesamt hab ich HTML Code aus Informationen
einer Klasse generiert.

Sinngemäss sowas:


```
News news = Something().getContent().getNews();
String title = news.getTitle();
String whatever = news.getWhatever();
stringBuilder.append( "<span>" + title + "someotherhtmltags etc" + whatever +" usw");
```

Er hat mir jetzt gesagt, dass ich die lokalen Strings nicht erstellen soll, weil sie
Speicher fressen. Ich solle also den html String so erstellen:


```
stringBuilder.append( "<span>" +  Something().getContent().getNews().getTitle() + "someotherhtmltags etc" +  Something().getContent().getNews().getWhatever()+" usw");
```

Das ist jetzt vllt schwer auf die Situation zu übertragen, zumindest war es so dass
das ganze ein ellenlanger total unübersichtlicher String war.

Am meisten konnte ich folgendes nicht nachvollziehen:
Statt meiner Variante - Logik von der HTML-Generierung zu trennen - :


```
News news = Something().getContent().getNews();
String title = news.getTitle();
String whatever = news.getWhatever();
String imgPath = null;
if(news.hasImage()){
     String tempPath = news.getImage();
     File f = new File(tempPath);
     if(f.canRead() && f.exists()){
          imgPath = tempPath;
     }
}

// html bauen:
stringBuilder.append(...);
if(imgPath != null){
     stringBuilder.append("src= blablabla" +  imagePath + "usw...");
}
```

hat er folgendes gemacht:


```
stringBuilder.append( "<span>" +  Something().getContent().getNews().getTitle() + "someotherhtmltags etc" +  Something().getContent().getNews().getWhatever()+" usw");
if(Something().getContent().getNews().getImage() != null){
     File f = new File(Something().getContent().getNews().getImage());
     if(f.canRead() && f.exists()){
         stringBuilder.append("src= blablabla" +  Something().getContent().getNews().getImage() + "usw...");
     }
}
```

Seine Begründung wieder: "Du sparst dir den lokalen String imgPath".

So also ich hab mit ihm drüber geredet und langer Rede kurzer Sinn:

Er meinte er will keine unnötigen Objekte erstellen, weil Strings sehr teuer sind.
Das glaub ich ja, hab ich auch oft gehört. Okay, also erstell ich keine lokalen Strings mehr,
obwohl das ja eig. auch nur Referenzen speichert, meinte er dass da eine String-Tabelle
durchsucht wird ob es den schon gibt, und das kostet Zeit.
Er sagte einfach Strings sind eine Ausnahme weil sie wie Primitive behandelt werden.
Also gut, damit kann ich leben.

Aber nichmal Referenzen auf "echte Objekte" darf ich machen:


```
News news = Something().getContent().getNews(); // <-- nich mal das!
```

..sondern soll bei jedem Aufruf über  Something().getContent().getNews() gehen.
Weil's die Referenz ja schon gibt.
Aber mein news-Objekt ist ja nicht "new", also auch nur eine Referenz = 4 Byte?

Also ich weiss nicht. Türlich ist er sicherlich besser als ich im Programmieren, aber ich wollte
einfach hier mal nachfragen.

Ist das echt so krass, dass man das so macht? Keinerlei lokale Hilfs-Variablen usw
erstellen, sondern lieber ellenlange unübersichtliche Code-Zeilen haben, nur weil man damit
ein paar Byte im Speicher oder Rechenzeit spart?

Der komplette Code den er schreibt sieht so aus, für mich total unübersichtlich.
Ist einfach das komplette Gegenteil von der Art, wie ich eig. code:
Sobald ich an einer Stelle mehr als einmal eine Info von aussen brauch, speicher
ich mir die lokal in einer Referenz ab, und nutz dann diese, statt jedesmal wieder
die Methoden von aussen aufzurufen.

Wie is das so bei euch "anderen"? Könnt ihr das bestätigen oder nicht?

Danke

*PS:* Wie kann ich eig. testen um wieviel Speicherplatz mehr lokale
Referenzen brauchen?
Ich hab über Runtime.getRuntime().totalMemory() gelesen aber das bringt mir
irgendwie immer den gleichen Wert, total egal was für Objekte oder so ich erstelle...

PPS: Ich hab grad ein Test String vs StringBuilder gemacht. Ist StringBuilder nur
schneller oder braucht er auch weniger Speicher?


----------



## 0x7F800000 (24. Feb 2009)

Wie es so bei "anderen" ist würde ich zugerne zur Abwechslung mal am eigenen Hirn ausprobieren, aber ich kann dir mal sagen, was bei einem einfachen test rauskommt:

A B und C sind im wesentlichen Klassen mit gettern und einfachen Konstruktoren, die referenzen auf jeweils den nächsten bzw ein integer speichern. Der test sieht so aus:
[HIGHLIGHT="Java"]
public class TEST {
public static void main(String... args){

	A a=new A(new B(new C()));

	long n=Integer.MAX_VALUE;

	//einfach ein bisschen auf den rechner einprügeln, bis der kühler voll aufdreht
	for(int i=0; i<n; i++);

	//Versuch 0: nichts machen
	long tNull=System.currentTimeMillis();
	for(int i=0; i<n; i++);
	tNull=System.currentTimeMillis()-tNull;

	// Versuch 1: mit referenz
	long tRef=System.currentTimeMillis();
	C c=a.getB().getC();
	for(int i=0; i<n; i++) c.setX(0);
	tRef=System.currentTimeMillis()-tRef;

	// Versuch 2: direkter zugriff
	long tDir=System.currentTimeMillis();
	for(int i=0; i<n; i++) a.getB().getC().setX(0);
	tDir=System.currentTimeMillis()-tDir;

	// Versuch 3: rechnen
	long tCalc=System.currentTimeMillis();
	double d=-100000000d;
	for(int i=0; i<n; i++) d+=0.01;
	tCalc=System.currentTimeMillis()-tCalc;


	System.out.println(
			"Nix machen:\t"+tNull+
			"\tMit referenz:\t"+tRef+
			"\tDirekt:\t"+tDir+
			"\tRechnen:\t"+tCalc);
}
}
[/HIGHLIGHT]

Ergebnis (2x2.1GhZ 4GB ram, 32bit BS):


> Nix machen:	6301
> Mit referenz:	6402
> Direkt:	6334
> Rechnen:	6228


geil oder? Ich weiß echt nicht, was das Programm tut. Aber deinem chef kannst du dafür danken, dass er im vergleich zu deiner methode ~1.09% performance einspart. Tolle Sache.
Ferner kannst du dem erzählen, dass er in seinen code sinnfreie Rechungen mit doubles einbauen soll, als "schmieröl", damit der rechner schneller läuft^^    Ich hab echt keine Ahnung, warum das Rechnen mit doubles schneller ist als NICHTS zu tun. 

Aber daraus kann man offenbar sehen, dass solche Kleinigkeiten absolut scheißegal sind.


----------



## 0x7F800000 (24. Feb 2009)

Bei Strings könnte es schon anders aussehen, da wird tatsächlich viel dumm hinundherkopiert, probier's doch einfach aus...

Was mir an deinem code jetzt aber wesentlich suspekter vorkommt: wieso schreibst du überhaupt irgendwelchen html-Kram auf diese Weise? Wofür gibts JSTL und das alles  Hab ich schon wieder irgendeine Entwicklung verpasst?^^


----------



## hdi (24. Feb 2009)

Andrey, danke für die Antwort erstmal.
Das mit der Rechenzeit ist ja eh bekannt, dass das immer unterschiedlich ist.
Double-Rechnungen machen das sicher nicht schneller, war grad Zufall und hängt
auch vom Scheduling und anderen Sachen an.

Mach das mal 1000 mal, ich denke nicht dass Doubles immer schneller sein werden
als nix.

Aber mir geht's mehr um den Speicherverbraucht.

Siehe mein "PS" und "PPS" im obigen Beitrag (unten editiert).

Kannst du dir dafür auch noch was einfallen lassen?

edit: Wegen dem HTML: Tja kA das war meine Aufgabe. Der Chef macht häufiger Dinge etwas umständlich wie ich finde


----------



## 0x7F800000 (24. Feb 2009)

Ööööh... speicherverbrauch? Was für Speicherverbrauch? Speicherverbrauch für eine Referenz? Ein WORD? 32bits? 4bytes? Weißt du was, ich bin ein kleiner unbedeutender Mensch mit einem kleinen unscheinbaren Laptop, ich hab da 4GB RAM drin. Das reicht für eine Milliarde solcher referenzen. Um auch nur 1% von meinem Speicher mit "unnötigen referenzen" vollzumüllen, müsstest du in deinem Code 10.000.000 unnötige Referenzen reinbauen. Du hast soviele referenzen im Leben nicht eingetippt. 
Wenn du bei jeder Referenz 1 Sekunde lang nachdenkst und tippst, brauchst du etwa 4 Monate reiner Schreibarbeit ohne Unterbrechungen auf schlaf, essen, toilette usw. Das schafft kein Menschliches Wesen. Kein Menschliches wesen ist in der Lage 1% von meinem speicher mit sinnlosen Referenzen vollzumüllen. Zumindest bei einfachen sequentiell aufgerufenen Methoden....

Wenn das eine rekursive methode ist, und eine referenz plötzlich Milliardenfach bei großen Rekursionstiefen vorkommen kann, dann ist der StackOverflowError natürlich garantiert, aber das kriegst du auch so früh genug mit.

Daher sind diese O(1)-einsparungen imho völlig sinnfrei.
Aber ich würde dem Chef mit diesem Argument so nicht kommen. Der hat's wahrscheinlich nur so nebenbei gesagt, weil er absolut nicht leiden kann, wenn der code mit "unnötigen" bzw "eliminierbaren" variablen gefüllt wird, vielleicht mag er direkten Zugriff einfach lieber, hält das für übersichtlicher. Das wird wohl der Grund sein. Und bei Strings hat er wohl einfach nur recht, egal wie man das interpretiert.


----------



## hdi (24. Feb 2009)

Widersprechen tu ich dem da eh nich  Ich will es nur wissen, weil ich's etwas strange fand.

Du sagst ja selber dass es völlig wurscht ist ob ich mir ne Referenz speicher.
Was heisst mit Variablen zumüllen? Mein Code ist gut lesbar und verständlich.

Also ich weiss nich, das regt mich ein wenig auf irgendwie. Der Code sah echt mal krass
scheisse aus, in jeder Zeile vier Umbrüche weil es so lang ist, und irgendwelche if-Abragen
mittem im StringBuilder nur damit ich mir einen gottverdammten lokalen String spar.
Das ist doch nicht guter "Stil" 

Heutzutgage muss man doch bei einfachen Berechnungen nicht an Performance oder
Speicherbedarf denken. Ein paar Referenzen lokal erstellen zur besseren Lesbarkeit,
Code nach der Logik her trennen auch wenn mich das wieder ein paar extra Zeilen oder
lokale Hilfs-Variablen kostet...
Aber das is doch alles *gut* zu machen, so hab ich's gelernt 

Ich hab mir halt Mühe gegeben das schön zu coden, und dann kommt er und ändert alles ab,
genauso wie ich es halt extra vermieden hab..


----------



## 0x7F800000 (24. Feb 2009)

hdi hat gesagt.:


> Was heisst mit Variablen zumüllen? Mein Code ist gut lesbar und verständlich
> ...
> Also ich weiss nich, das regt mich ein wenig auf irgendwie. Der Code sah echt mal krass
> scheisse aus, in jeder Zeile vier Umbrüche weil es so lang ist, und irgendwelche if-Abragen
> mittem im StringBuilder nur damit ich mir einen gottverdammten lokalen String spar.



Jetzt bitte nichts persönlich nehmen hier, den code hab ich nicht gesehen^^ ich bin mir eigentlich sicher, dass du den code nicht mit unnötigen variablen "zumüllst", aber es gibt eben auch welche, bei den sieht's dann so aus:
[HIGHLIGHT="Java"]
public int add(int x, int y){
   int a=x;
   int b=y;
   int r=x+y;
   int t=r;
   return -(-t);
}
[/HIGHLIGHT]
oder sowas... Ne, das ist jetzt auch krass übertrieben, aber ich hab grad keine Lust nach so einem beispiel zu suchen, aber es gab hier vor kurzem so einen...

Vielleicht ist dein chef grad das andere Extremum? Solange er damit selbst gut klarkommt, und alles (nach der gewöhnungsphase^^) verständlich aussieht, dann kann man dagegen eigentlich nicht viel einwenden. Aber ob's jetzt sinnvoll ist, dir bei solchen kleinigkeiten einen ungewohnten code-stil aufzuzwingen? Ich glaube eher nicht... naja, warten wir mal bis morgen, was die Profis so sagen 

Dein Problem ist wohl weniger der stil, sondern das erwartete jedoch nicht eingetretene Erfolgserlebnis, kann das sein?  Nja, passiert halt, da soll man nicht zu voreilig urteilen


----------



## marasek (24. Feb 2009)

Hnng...naja, noch besser war mal eine elendslange Diskussion in der PHP-NG, ob ' oder " bei Strings performanter ist...

Speicher & Performance wird meiner Ansicht nach verbraten, wenn man zuviel abstrahiert und dann Zeugs macht, dass zwar OOP völlig in Ordnung ist, aber Schwachsinn ist, wenn man näher hinguckt - mein Favorit ist ORM, wenn man über alle, say, Objekte Buch rüberiteriert und in der Schleife diejenigen löscht, die eine bestimmte Bedingung erfüllen - etwas, das mit einer direkten SQL-Abfrage WESENTLICH performanter käme.

HTML als Concatenationsgematsche zu erzeugen finde ich gruselig und man holt sich die XSS-Lücken geradezu ins Haus, denn da mal das htmlentities() [PHP-Funktion] zu vergessen passiert schnell. Daher mache ich das seit Jahren so (in PHP):


```
$input["type"] = "text";
$input["value"] = "Angela Merkel";
$input["name"] = "person";
if($this->disabled==true) {
    $input["disabled"] = "disabled";
}

$html = Basic::xmltag("input", $input);
//bzw.
$html = Basic::xmlEnclose("a", $a, "Angela Merkel");
```

Wesentlich eleganter, wenn man noch Bedingungen drin hat. Letzlich ist das strukturierter und sollte je ein zusätzlicher Speicherriegel fällig werden, dann ist das immer noch billiger als vier Stunden Entwicklerzeit vorm Debugger. Wobei ich in der Praxis immer noch 8 MB memory limit drin stehen habe. Sich um den Speicherverbrauch von Strings Gedanken zu machen kommt mir vor wie auf einer vollen Festplatte erst mal die README's zu löschen und die Filme draufzulassen ;-).


----------



## hdi (24. Feb 2009)

> Dein Problem ist wohl weniger der stil, sondern das erwartete jedoch nicht eingetretene Erfolgserlebnis, kann das sein?


Nein also klar in dem Moment sass ich erstmal da und achte hm okay..
Aber das hat mich jetzt nich tief in der Seele verletzt 

Es interessiert mich jetzt einfach, weil das mein erster Kontakt mit einem "professionellen"
Programmierer ist, also der das hauptberuflich macht, so wie ich mal später.

Und ich bin einfach etwas geschockt wenn ich mir im Project die Source-Files ansehe,
und dann halt von ihm diese Dinge zwecks "Speicherplatz sparen" höre.
Ist einfach nicht das, was ich in der Uni gelernt hab.

Und jetzt will ich wissen: Wer hat Recht? Er, oder die Uni?

Und ich weiss ich konnte jetzt auch nur mit einem erfundenen Bsp kommen, aber
ich hab wirklich keine bescheuerten Variablen erstellt.

Die Methode hat nen StringBuilder bekommen und anhand von Infos aus einem Objekt,
das sie auch bekommen hat, einen HTML-Code erzeugt.

Rein von der Optik und der Logik hab ich es so gemacht, dass ich erst die Objekt-Infos
auslese, dort auch die Logik übernehmen (s.o. mit dem Bild-Check),
und ein StringBuilder ist für mich etwas, dass Strings zusammenbaut, und nicht mehr.

Ich denke mir also, wenn jmd den Code gut und schnell verstehen soll, sollte das am 
Ende so aussehen:

builder.append(title);
builder.append(publishDate);
builder.append(message);
builder.append(link);

Weil das macht die Methode, und man sieht an diesen Zeilen halt wie später die Anzeige
in der HTML-Seite ist, alleine durch die Namen.

Das find ich halt richtiger als das alles zusammenzuschmeissen und eine immer wieder
kehrende ellenlange Methoden-Kombination mitten in diese append-Anweisungen reinzuwerfen, oder
sogar irgendwelche Background-Logik da reinzuziehen.

Wichtiger als vllt 40 byte Speicher zu sparen. Und man überlege es ist ja ne kleine Methode, in der man sich ~ 1 ms aufhält. 
Der GC wird diese 40 byte eh sofort wieder freigeben weil alles lokale verschwindet.

ka


----------



## 0x7F800000 (24. Feb 2009)

Tsshh... Die php-Tags haben die grade wieder weggemacht aus dem WYSIWYG-Editor? Mist^^ 


> Letzlich ist das strukturierter und sollte je ein zusätzlicher Speicherriegel fällig werden, dann ist das immer noch billiger als vier Stunden Entwicklerzeit vorm Debugger.


Das hört sich doch vernünftig an  Vor allem so human^^


----------



## byte (24. Feb 2009)

Die "Optimierung" Deines Chefs halte ich für Schwachsinn. Lokale Variablen werden vom Compiler sowieso wegoptimiert.

Stattdessen hätte er mal die ganzen String-Konkatenationen mit dem + Operator wegoptimieren sollen. Das wäre das einzige, was man meiner Meinung nach beanstanden könnte an dem Code.


----------



## schalentier (24. Feb 2009)

```
getSomething().getContent().getNews().getTitle()
```

Wenn ich sowas sehe, stellen sich meine Fussnaegel hoch... Hat sich dein Chef eigentlich mal ueberlegt, was passiert, wenn eine dieser Methoden null zurueckliefert? 

Wieso sollte das schneller sein, als die "Zwischenergebnisse" in lokalen Variablen zu speichern? Immerhin muss das immer wieder aufgerufen werden. Wenn also getSomething() z.B. zuerst mal in einer DB nachsieht... dann passiert das bei jedem dieser Zugriffe. Was so ca. 100000x langsamer sein wird, als die lokale Variable. Selbst wenn da keine DB ist, sind das jeweils vier Methodenaufrufe, die sicherlich auch kein final in ihrer Signatur haben... also kostet auch die Polymorphie noch etwas... nich das das langsam waere, aber sicherlich dauerts laenger, als die lokale Variable... 

Oder was passiert in einer multithreaded Umgebung? Was, wenn getSomething() nach 2 Aufrufen etwas anderes zurueckliefert, weil dort eine Aenderung durch eine andere Session durchgefuehrt wurde?

Hirnverbrannt, wenn du mich fragst.


----------



## tfa (24. Feb 2009)

Ich finde auch, dein erster Ansatz war absolut richtig und der Frickelei des Chefs vorzuziehen. Ein gut durchschaubarer Code ist allemal besser als ein paar Millisekunden (vermeindlichen) Geschwindigkeitsvorteil. 
Strings sind nicht teuer, kurzlebige lokale Strings noch viel weniger. Von Referenzen ganz zu schweigen. Wenn es irgendwo einen Flaschenhals gibt (irgendeine Schleife, die Millionen mal pro Sekunde aufgerufen werden soll), kann man natürlich alle möglichen Schweinereien machen. Aber nicht einfach nur so. 
Frag mal deinen Chef, ob er die drei Regeln der Optimierung kennt.


----------



## SlaterB (24. Feb 2009)

byto hat gesagt.:


> Stattdessen hätte er mal die ganzen String-Konkatenationen mit dem + Operator wegoptimieren sollen. Das wäre das einzige, was man meiner Meinung nach beanstanden könnte an dem Code.


wobei viele + in einer Zeile nicht proportional zur Anzahl der + Zeichen inperformanter sind, sondern nur unübersichtlich,

schlimmer im Sinne der Performanz ist
a += b;
a += c;
a += d;
usw


----------



## tfa (24. Feb 2009)

Stringzusammenbauten mach ich am liebsten mit printf bzw. format:

[HIGHLIGHT="Java"]String content = String.format("<b>%s</b> - <i>%s - %s</i>; %s,%2.2i", datum,
                                                                       getContent().getZeile1(),
                                                                       getContent().getSumme(),
                                                                       getWert().getKurztext(),
                                                                       durchschnitt);[/HIGHLIGHT]
Sieht halbwegs übersichtlich aus, ist aber wahrscheinlich mit Abstand am unperformantesten.


----------



## Zed (24. Feb 2009)

Stellt ich das Something().getContent().getNews().getImage() mal auf 2000 Zeilen Code oder noch mehr Zeilen  vor. Da kriegt man ja Angst. 

Der macht das bestimmt schon seit Jahren / Jahrzehnten so. 

Wie ist das eigentlich beim Stringbuilder? Ich mach immer in der append-Methode höhstens 10 String-Konkatenationen mit dem + Operator. Gibts da ne Faustregel wie viele es nun max. sein sollen?


----------



## tfa (24. Feb 2009)

Wenn du schon den StringBuilder benutzt, am besten null


----------



## Landei (24. Feb 2009)

tfa hat gesagt.:


> Stringzusammenbauten mach ich am liebsten mit printf bzw. format:
> 
> [HIGHLIGHT="Java"]String content = String.format("<b>%s</b> - <i>%s - %s</i>; %s,%2.2i", datum,
> getContent().getZeile1(),
> ...



Würde ich nicht sagen, denn intern wird ja sicher ein StringBuilder verwendet. Ich mache es übrigens auch so.


----------



## Zed (24. Feb 2009)

tfa hat gesagt.:


> Wenn du schon den StringBuilder benutzt, am besten null



Die ganze Zeit append in folge nervt.


----------



## Noctarius (24. Feb 2009)

byto hat gesagt.:


> Stattdessen hätte er mal die ganzen String-Konkatenationen mit dem + Operator wegoptimieren sollen. Das wäre das einzige, was man meiner Meinung nach beanstanden könnte an dem Code.



Also ich denke, dass jeder gute Compiler da mitlerweile intern StringBuilder draus baut oder sehe ich das falsch? Getestet hab ich das nicht, aber ich denke SUN ist ja auch nicht ganz dumm 

Abgesehen davon benutze ich beim Zusammenbauen von größeren Strings auch immer direkt den StringBuilder (wer weiß mit was später kompiliert wird) bei kleineren Concatinations so 2 oder 3 Strings benutze ich auch den +-Operator (schade auf mein Haupt, ich weiß )


----------



## byte (24. Feb 2009)

Zed hat gesagt.:


> Die ganze Zeit append in folge nervt.



Dann schreib Dir einen Helper:

[HIGHLIGHT="Java"]    public StringBuilder append(String...args) {
        StringBuilder result = new StringBuilder();
        for (String string : args) {
            result.append(string);
        }
        return result;
    }[/HIGHLIGHT]


----------



## SlaterB (24. Feb 2009)

tztz, 
da wird ja ein sinnloses String[] für die Parameter-Übergabe erzeugt,
das als Performanz zu verkaufen kann wohl nur Ironie sein 


(spätes edit: im Verhältnis zu eingesparten Zwischenstrings kann dieser kleine konstante Zusatzaufwand aber durchaus akzeptabel gering sein,
wäre im Zweifel zu testen)


----------



## Noctarius (24. Feb 2009)

Hat eigentlich wer Erfahrungen bezüglich String.concat? ^^


----------



## maki (24. Feb 2009)

> Er hat mir jetzt gesagt, dass ich die lokalen Strings nicht erstellen soll, weil sie
> Speicher fressen.


Dein Chef ist ein Schwachkopf und hat keine AHnung 

Mal im ernst:
Wer solche Behauptungen ohne Profiler aufstellt will sich nur profilieren und verbessert meist gar nichts am Code.


----------



## SlaterB (24. Feb 2009)

@Noctarius:

kannst hier mal reinschauen:
http://www.java-forum.org.server659-han.de-nserver.de/showthread.php?t=50804


----------



## byte (24. Feb 2009)

SlaterB hat gesagt.:


> tztz,
> da wird ja ein sinnloses String[] für die Parameter-Übergabe erzeugt,
> das als Performanz zu verkaufen kann wohl nur Ironie sein



Stimmt. Hab ich nicht bedacht.


----------



## tfa (24. Feb 2009)

> Also ich denke, dass jeder gute Compiler da mitlerweile intern StringBuilder draus baut oder sehe ich das falsch?


Die String-Konkatenation mit + wird vom Compiler schon immer durch StringBuilder (bzw. früher StringBuffer) ersetzt. Wenn möglich, werden sogar Stringkonstanten erzeugt (bei "Literal"+"Literal").


----------



## Noctarius (24. Feb 2009)

SlaterB hat gesagt.:


> @Noctarius:
> 
> kannst hier mal reinschauen:
> http://www.java-forum.org.server659-han.de-nserver.de/showthread.php?t=50804



lol nice discussion  - wenigstens war mir jetzt für 15min nicht langweilig


----------



## Noctarius (24. Feb 2009)

tfa hat gesagt.:


> Die String-Konkatenation mit + wird vom Compiler schon immer durch StringBuilder (bzw. früher StringBuffer) ersetzt. Wenn möglich, werden sogar Stringkonstanten erzeugt (bei "Literal"+"Literal").



Beim SUN-Compiler  Es gibt aber auch Andere: z.b. IBM, coffein usw. Ich würde diese Aussage nicht verallgemeinern und mich schon garnicht darauf verlassen, dass es immer so ist. Wie das Ganze vom Compiler in Bytecode umgesetzt wird ist schlicht nicht definiert, der Bytecode muss nur tun was man erwartet.

Dass nicht gleich umgesetzt wird zeigen ja schon Native-Compiler wie der gcj der zwangsweise (schon vom Ergebnis her) nicht in Bytecode kompilieren kann.

Ergo ist es meiner Meinung nach besser an gewissen Dingen nicht nur den Compiler teilhaben zu lassen. Aber bei Dingen wie lokalen Referenzen stimme ich den Anderen zu, da dürfte jeder einigermaßen aktuelle Compiler seine Finger dran haben und diese "wegoptimieren".

Schöner ist es dann wenn Leute ankommen und behaupten die Leerzeilen und Kommentare sind Schuld, wenn die VM "laggt" *hust*
Ein kleiner Hinweis das Thema Bytecode nachzulesen stimmte Ihn dann schneller ruhig als ich die Diskussion anfangen konnte


----------



## maki (24. Feb 2009)

> Ergo ist es meiner Meinung nach besser an gewissen Dingen nicht nur den Compiler teilhaben zu lassen. Aber bei Dingen wie lokalen Referenzen stimme ich den Anderen zu, da dürfte jeder einigermaßen aktuelle Compiler seine Finger dran haben und diese "wegoptimieren".


Hmm.. weiss nicht, würde trotzdem StringBuilder nur in Schleifen einsetzen.

http://java.sun.com/developer/technicalArticles/Interviews/community/kabutz_qa.html


----------



## hdi (24. Feb 2009)

> Also ich denke, dass jeder gute Compiler da mitlerweile intern StringBuilder draus baut oder sehe ich das falsch?



Ich hab zB gestern gestestet: 100.000 Konkatenation mit Strings und mit StringBuilder.
Strings: ~4 sekunden
StringBuilder: 0 ms

1.000.000 Konkatenationen:
StringBuilder: 0 ms !!
Strings: ...hab nach 5 min abgebrochen...

ich weiss nicht, was für einen Compiler ich hab. JDK 6U12 mit Eclipse Ganymede


----------



## maki (24. Feb 2009)

Micro Benchmarks sind mit vorsicht zu geniessen, oft liefern sie falsche Ergebnisse, siehe HDIs ergebnisse 



> Also ich denke, dass jeder gute Compiler da mitlerweile intern StringBuilder draus baut oder sehe ich das falsch?


Richtig, jeder halbwegs gute Compiler macht das, wenn möglich.


----------



## hdi (24. Feb 2009)

@maki was soll das heissen? Hier mein Test:


```
public class StringVsStringBuilder {

	public static void main(String[] args) {

		for (int runs = 10; runs <= 1000000; runs *= 10) {
			System.out.println(runs + " runs:");
			strings(runs);
			stringbuilder(runs);
		}
	}

	private static void stringbuilder(int runs) {
		long start = System.currentTimeMillis();
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < runs; i++) {
			sb.append("x");
		}
		long end = System.currentTimeMillis();
		long time = (end - start) / 1000;
		System.out.println("\tstringbuilder: " + time + " seconds.");
	}

	private static void strings(int runs) {
		long start = System.currentTimeMillis();
		String s = new String();
		for (int i = 0; i < runs; i++) {
			s += "x";
		}
		long end = System.currentTimeMillis();
		long time = (end - start) / 1000;
		System.out.println("\tstrings: " + time + " seconds.");
	}

}
```

	// RESULT:
	//
	// 10 runs:
	// strings: 0 seconds.
	// stringbuilder: 0 seconds.
	// 100 runs:
	// strings: 0 seconds.
	// stringbuilder: 0 seconds.
	// 1000 runs:
	// strings: 0 seconds.
	// stringbuilder: 0 seconds.
	// 10000 runs:
	// strings: 0 seconds.
	// stringbuilder: 0 seconds.
	// 100000 runs:
	// strings: *14 seconds*.
	// stringbuilder: 0 seconds.
	// 1000000 runs:
	// strings: *??? minutes*
	// stringbuilder: 0 seconds.

MicroManagement ist klar insofern, weil man wohl selten 100.000 Strings konkateniert.
Alles darunter bleibt ja auch bei Strings ~0 ms.
Aber was kann an dem Ergebnis "falsch" sein?

Offenbar kompiliert der Compiler hier nix weg, sonst würde es nicht so lange dauern.
Und ich hab doch keinen seltsamen Compiler oder? Wie gesagt: Einfach Eclipse und Java
installiert, oder fehlt mir hier was tolles ?


----------



## SlaterB (24. Feb 2009)

das soll heißen, dass Optimierung über Schleifen hinweg nie ein Thema war sondern nur

String x = "a"+"b"+"c"+"d"+"e"+"f";


----------



## Noctarius (24. Feb 2009)

Schau dir den Thread an den Slater mir gegeben hat (paar Posts drüber) dann weißt du warum.

Solche Mini-Benchmarks haben immer einen gewissen Reiz sind aber nicht zwangsläufig richtig, da nicht nur verschiedene Java-Compiler unterschiedlichen Bytecode erzeugen können, sondern der Hotspot-Compiler (JIT) auch zur Laufzeit aggressive Optimierungen vornimmt wo es Sinn macht -> http://de.wikipedia.org/wiki/Hotspot-Optimierung


----------



## maki (24. Feb 2009)

> @maki was soll das heissen?


Das soll heissen dass dein test falsche Ergebnisse liefert, um das zu wissen braucht man nichtmal den Code zu sehen, denn "Stringbuilder braucht 0 sekunden) kann einfach nicht sein.
Du bist auf Compiler Optimierungen bzw. den Hotspot reingefallen.

Tipp 1: Verwende kein konstantes Stringliteral ("x"), sondern einen Paramter.
Tipp 2: Mach es mal mit, mal ohne Schleife, in letzterem Fall gibt es keinen Unterschied, denn es wird ein StringBuilder verwendet, der vom Compiler anstatt des String + eingesetzt wurde.
Tipp 3: Dekompilieren, Code ansehen.

Wenn du das alles richtig machst, wirst du nix anderes beweisen als schon längst bekannt war:


> würde trotzdem StringBuilder nur in Schleifen einsetzen.



Die Moral?
Vergiss Micro-Benchmarks, wenn dein programm zu langsam läuft, optimiere nach dem du es durch einen Profiler gejagt hast.


----------



## hdi (24. Feb 2009)

@slater: ok 



> Frag mal deinen Chef, ob er die drei Regeln der Optimierung kennt.


Wie lauten die denn? Spontantes googlen gab keine Treffer.


----------



## byte (24. Feb 2009)

Man könnte es der JRE evtl. etwas schwerer machen, da was wegzuoptimieren, indem man einen nicht berechenbaren Wert konkateniert (z.B. einen Wert per _java.util.Random_).


----------



## tfa (24. Feb 2009)

hdi hat gesagt.:


> Wie lauten die denn? Spontantes googlen gab keine Treffer.



1. Tu's nicht!
2. Lass es!
3. Vielleicht später wenn's nötig ist (Experts only)


----------



## maki (24. Feb 2009)

hdi,

mal eine andere Frage:
Warum erzeugt ihr HTML Tags in Java?
Ist das eine WebApp?


----------



## Javalist (24. Feb 2009)

Ich sag dazu: "Willkommen in der Wirklichkeit"

Gewöhn Dich dran, dass Du in Deinem Beruf immer wieder auf solche Probleme stossen kannst und wirst. Und eben nicht immer wird ein Kompromiss zu finden sein.
Ich kenne einen Entwickler, der JavaDoc löscht, weil: "Die Klassen werden dann so lang und unübersichtlich und unnötig groß". Jegliche Diskussion verlaufen im Sand.

Ich würde an Deiner Stelle versuchen so zu argumentieren, dass Du dann Deinen Code besser überblickst und deswegen so weitermachen wirst. Komm nicht an mit "Aber auf der Uni..."

Viel Spaß weiterhin


----------



## Noctarius (24. Feb 2009)

> Ich kenne einen Entwickler, der JavaDoc löscht, weil: "Die Klassen werden dann so lang und unübersichtlich und unnötig groß".



Dazu fällt mir spontan nur (k)ein Wort ein: OMG! ^^


----------



## schalentier (24. Feb 2009)

Javalist hat gesagt.:


> Ich kenne einen Entwickler, der JavaDoc löscht, weil: "Die Klassen werden dann so lang und unübersichtlich und unnötig groß". Jegliche Diskussion verlaufen im Sand.




```
/**
 * This getter gets the name
 *
 * @return the name
 */
public String getName() {..}

/**
 * This setter sets the name
 *
 * @param name the name to set
 */
public void setName( String name ) {..}
```

JavaDoc ist schon ultrawichtig :-D


----------



## Noctarius (24. Feb 2009)

Lassen wir mal die Standard-Eclipsetexte außen vor


----------



## 0x7F800000 (24. Feb 2009)

Ne, ich verstehe überhaupt nicht worüber der chef sich überhaupt sorgen macht. Diese ganzen lustigen ruby's und php's laufen doch auch beim optimalen code schon um ~Faktor 100 langsamer, aber da beschwert sich dennoch keiner... Java Programme sind da im Vergleich schon nicht die kürzesten, wenn man sich dann nach einem halben jahr solchen code wie den von deinem chef anschauen muss, dann rafft man doch gar nichts mehr. Mit etwas Übung schafft man das zum laufen zum bringen, vielleicht auch ohne 4 Stunden am Debugger zu hocken, dagegen wird die Wartbarkeit durch solchen Stil imho drastisch reduziert.


----------



## Marco13 (24. Feb 2009)

Habe nicht alles im Detail gelesen, aber beim an-lesen des ersten Beitrages dachte ich mir spontan nur sowas wie "Bockmist". Da werden sicher auch subjektive einflüsse drin sein. Aber .... die Bisherigen Antworten scheinen ja auch eine deutliche Aussagen zu enthalten.


----------



## hdi (24. Feb 2009)

Hm naja gut also ich sehe: Es ist zumindest kein unumstösslicher Codex es so zu machen,
wie mein Chef sagte..
Passt schon ich werd einfach weiter coden wie ich denke, und wenn er's ändern will...
Ja mein Gott soll er halt.
Wenn's dann Probleme mit dem Code gibt gibt soll er das bitteschön debuggen.

@maki:
Ja eine Web-App, es werden News in News-Objekten gespeichert, die haben halt
dann ihre Attribute "Titel", "Link", "bild" usw.

Die Methode bekommt ein News-Objekt, liest die Infos über getter aus und erstellt
per StringBuilder einen kompletten HTML-Code, der alle Formatierungstags enthält
und das ganze eben so zusammenbaut.

Dieser String wird dann dem Frontend überreicht und der pastet das nur noch in eine .jsp


----------



## maki (24. Feb 2009)

> @maki:
> Ja eine Web-App, es werden News in News-Objekten gespeichert, die haben halt
> dann ihre Attribute "Titel", "Link", "bild" usw.
> 
> ...


Erklär mal deinem Chef dass das sehr schlechtes Design ist, so etwas (HTML Tags) sollte man nicht im Javacode machen, ist nix anderes als Java Code in JSPs zu verwenden


----------



## SlaterB (24. Feb 2009)

kommt auf die Flexibilät des JSP an und die Komplexität des HTML-Strings,

ich mühe mich gerade, mit XSL ein XML-Dokument zusammenzubauen und wenn ich mir da die Template-Aufrufe, Variablen-Deklaration, Verzeigung, Vererbungsmöglichkeiten anschaue,
würde ich am liebsten auch alles durch Java-String-Zusammenbau ersetzen


----------



## hdi (24. Feb 2009)

> Erklär mal deinem Chef dass das sehr schlechtes Design ist


Vielleicht nächstes Jahr  Ich bin nur der Werkstudent, ich werd da meinen Vorgesetzten nicht dumm kommen.


----------



## maki (24. Feb 2009)

> ich mühe mich gerade, mit XSL ein XML-Dokument zusammenzubauen und wenn ich mir da die Template-Aufrufe, Variablen-Deklaration, Verzeigung, Vererbungsmöglichkeiten anschauen,
> würde ich am liebsten auch alles durch Java-String-Zusammenbau ersetzen


Ich sag ja nicht das ich das nicht auch schon gemacht habe bzw. nie machen würde *g*
Aber mit JSP+EL ist es mittlerweile nicht schwer zu verhindern dass man HTML in Java zusammenbauen muss.
Apache FOP zB. fand ich auch sehr ätzend.



> Vielleicht nächstes Jahr   Ich bin nur der Werkstudent, ich werd da meinen Vorgesetzten nicht dumm kommen.


Verständlich.


----------



## marasek (24. Feb 2009)

maki hat gesagt.:


> Erklär mal deinem Chef dass das sehr schlechtes Design ist, so etwas (HTML Tags) sollte man nicht im Javacode machen, ist nix anderes als Java Code in JSPs zu verwenden



So pauschal würde ich das nicht unterschreiben. Wenn man sich z. B. wiederverwendbare Widgets schreibt, muss man ja irgendwo HTML erzeugen.

Template-Systeme wie Smarty, mit denen man halbe Betriebssysteme in der Template-Sprache realisieren kann (und das dann auch gemacht wird), finde ich auch nicht so pralle.


----------



## maki (24. Feb 2009)

marasek hat gesagt.:


> So pauschal würde ich das nicht unterschreiben. Wenn man sich z. B. wiederverwendbare Widgets schreibt, muss man ja irgendwo HTML erzeugen.


Natürlich, zB. mit selbstgeschriebenen JSF/JSP Tags, aber so sieht das hier nicht aus


----------



## marasek (24. Feb 2009)

maki hat gesagt.:


> Natürlich, zB. mit selbstgeschriebenen JSF/JSP Tags, aber so sieht das hier nicht aus



Nun ja, von ein paar Zeilen Code will ich noch nicht auf die Qualität des Projekts schliessen. Auch ich hau manchmal ein "<tag>"+wert+"</tag>" raus (in PHP), weils an einer Stelle besser passt.

Allerdings, wenn ich ein leeres Eclipse und die Aufgabe, eine WA zu schreiben bekomme, dann sind die weiter oben erwähnten Methoden garantiert mit das erste, was ich mir programmieren werde.

Ich finde es manchmal ulkig, an welchen Stellen die Leute nicht automatisieren - da schreiben Leute in einem Projekt dutzende von Insert-Queries von Hand, anstatt sich eine Funktion zu schreiben, die eine Tabellennamen und eine HashMap frisst...


----------



## Wildcard (24. Feb 2009)

Noctarius hat gesagt.:


> Also ich denke, dass jeder gute Compiler da mitlerweile intern StringBuilder draus baut oder sehe ich das falsch? Getestet hab ich das nicht, aber ich denke SUN ist ja auch nicht ganz dumm


Das ist zwar richtig, es wird in der Regel ein StringBuilder verwendet, aber der Compiler kann nicht korrekt 'scopen'. Daher nimmt man händisch einen StringBuilder wenn es sich um eine Schleife, oder rekursive aufgerufene Methode handelt. Der Performanceunterschied geht dabei schnell in Faktor 1000 und mehr.


----------



## Ark (24. Feb 2009)

Was Laufzeitenverhalten angeht, habe ich ein Bild ähnlich dem folgenden im Kopf, das auf deutsche Autobahnen gemünzt ist (bitte um Kommentare):

Ganzzahloperationen/Dereferenzierungen -> Freie Fahrt!
Gleitkommaoperationen -> maximal 130 km/h
Methodenaufrufe -> dichter Verkehr
new -> Baustelle
synchronized -> Grenzübergang mit Grenzkontrolle
Schleifen -> "Ups, verfahren ^^" (Ehrenrunden )

Da dürfte der Code von deinem Chef, hdi, nicht besonders gut wegkommen. 

Ark


----------



## hdi (24. Feb 2009)

Nochmal um auf meine Frage ganz oben einzugehen:

Wie krieg ich raus wieviel Speicher mein Programm gerade im Moment belegt?

Mittels 		

[HIGHLIGHT="Java"]System.out.println(Runtime.getRuntime().totalMemory());[/HIGHLIGHT]

bekomm ich in *jedem* Programm, egal wie komplex oder unkomplex, 5056 kb raus.

Also das kann's ja nicht sein


----------



## SlaterB (24. Feb 2009)

leg ein 1.000.000er Array an, dann wirds ne andere Zahl


----------



## hdi (24. Feb 2009)

Ja aber korrekt kann das ja nicht sein oder?
Dass eine leere main-Methode 5056 frisst und genauso eine main-Methode
die gerade ein komplexes Objekt erstellt und einige Methoden (GUI, Thread) 
angeworfen hat, auch 5056 hat.


----------



## SlaterB (24. Feb 2009)

die Aussage ist korrekt soweit man das bei einer derart unscharfen Sache sagen kann,
du interpretierst sie nur falsch, musst noch 
Runtime.getRuntime().freeMemory()
abziehen, um den tatsächlich belegten Speicher zu bestimmen


----------



## Cody (24. Feb 2009)

@hdi:
Falls Du Eclipse verwendest, schau dir mal DAS PLUGIN an, evtl. bekommst Du ja so eine Antwort auf deine Frage


----------



## fjord (25. Feb 2009)

sehr komplex passt in 5056 kb aber nicht rein. 

totalMemory() sagt dir nicht wieviele Byte dein Programm belegt, sondern wieviele Byte deinem Programm gerade von der VM zur Verfügung gestellt werden. Wie du auf den Verbrauch kommst hat SlaterB ja schon beschrieben. Der Wert den du in jedem deiner Programme gefunden hast kommt daher, dass die VM dir einfach standardmäßig soviel zur Verfügung stellt. Wenn du mehr brauchst, wird totalMemory() auch mehr anzeigen, bis du bei maxMemory() angekommen bist, dann kommt die nette _java.lang.OutOfMemoryError: Java heap space_.


----------



## Sparkle (25. Feb 2009)

Hi,

Ich stimme den zweien hier zu:


byto hat gesagt.:


> Die "Optimierung" Deines Chefs halte ich für Schwachsinn. Lokale Variablen werden vom Compiler sowieso wegoptimiert.
> 
> Stattdessen hätte er mal die ganzen String-Konkatenationen mit dem + Operator wegoptimieren sollen. Das wäre das einzige, was man meiner Meinung nach beanstanden könnte an dem Code.





schalentier hat gesagt.:


> ```
> getSomething().getContent().getNews().getTitle()
> ```
> 
> ...



Wenn mir da spontan ein Fall einfallen würde, der "null" liefert, würde ich gleich mal genüsslich vor seinen Augen einen Testlauf damit machen und ihn dann den Fehler suchen lassen. Geht natürlich bei einem Chef nicht. Allgemein ist sowas echt nervig.

Dein Code ist um Meilen besser und ich würde fast Wetten eingehen, dass er nicht einen Deut langsamer ist. Was hier noch vergessen wurde, ist Wartbarkeit und Wiederverwendbarkeit. Letztere ist vielleicht noch gegeben bei passender Kapselung, aber ersteres kann man sich da völlig in die Haare schmieren, wenn kryptische Oschis epidemische Ausmaße annehmen.

Wie gesagt, bei einem Chef kann man sich sowas vielleicht sparen, wenn man nicht auf einer Linie liegt, ansonsten würde ich das auf jeden Fall anbringen, denn auf Dauer ist sowas schwer erträglich. Hilft ja keinem von beiden, wenn der eine Zeit verschwenden muss um zu kapieren, was der andere fabriziert hat.


----------



## Vayu (25. Feb 2009)

wenn ich den code deines Chefs sehen würde, würde ich mal eben den Ecipse refactoring mechanismus anschmeissen 

lokale variablen!!!!! Soviel power kann ein WebService gar nicht brauchen, dass man dafür auf die Wartbarkeit des Codes verzichtet ...

Schlechter Programmierer dein Chef.


----------



## maki (25. Feb 2009)

@hdi

https://visualvm.dev.java.net/


----------



## Vayu (25. Feb 2009)

cool das teil kannte ich noch nicht. Danke!


----------



## SchonWiederFred (26. Feb 2009)

SlaterB hat gesagt.:


> wobei viele + in einer Zeile nicht proportional zur Anzahl der + Zeichen inperformanter sind


Eigentlich wollte ich Dir ja widersprechen, aber Du hast offenbar Recht.
Hier ein kleines Testprogramm:

```
String a = "hello";
String b = "beautiful";
String c = "world";
String d = a + b + c;
```
Und hier der entsprechende Bytecode:

```
public static void main(java.lang.String[]);
  Code:
   0:	ldc	#16; //String hello
   2:	astore_1
   3:	ldc	#18; //String beautiful
   5:	astore_2
   6:	ldc	#20; //String world
   8:	astore_3
   9:	new	#22; //class java/lang/StringBuilder
   12:	dup
   13:	aload_1
   14:	invokestatic	#24; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
   17:	invokespecial	#30; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
   20:	aload_2
   21:	invokevirtual	#33; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   24:	aload_3
   25:	invokevirtual	#33; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   28:	invokevirtual	#37; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   31:	astore	4
   33:	return
```
Es wird tatsächlich nur ein StringBuilder erzeugt. Das war mir neu!


----------



## maki (26. Feb 2009)

Wie viele Threads über genau dieses Thema hatten wir eigentlich in den letzen 12 Monaten?
Denke es waren so einige.

Gerüchte sind eben schwer totzukriegen.


----------

