Stringaddition sehr langsam

Hallo Experten,

ich habe folgendes Problem: Ich möchte in meinem Javaprogramm größere Textdateien (ca. 300, 400 KB, ca. 3000 Zeilen Text) einladen. Das macht ich über einen BufferedReader und addiere dann auf einen Anfangsstring text jede neue Zeile auf, die ich einlese. Somit ergibt sich dann pro Datei ein Textstring mit dem gesamten Dateiinhalt.

Bereits bei 4 Dateien braucht das Laden allerdings schon 30 Sekunden. Hab lange gebraucht bis ich gemerkt habe, dass es an der Stringaddition liegt und nicht am FileReader. Lade ich die einzelnen Zeilen einfach in ein StringArray, so verkürzen sich nämlich die 30 Sekunden auf 0,… Sekunden.

Das Problem ist, dass ich die eingelesenen Dateien später durchsuchen und bearbeiten möchte, d.h. ich brauche wirklich einen String pro Datei. Meine Frage ist jetzt, ob es eine Methodik gibt, welche die Stringaddition in irgendeiner Form verkürzen würde. Ich hab schon probiert erst mal alles in eine ArrayList zu packen und diese dann mit toString() in einen String umzuwandeln - braucht jedoch genauso lange. Gibt es da noch was anderes? Oder kennt jemand vielleicht eine andere Vorgehensweise für dieses Problem (z.B. Datei direkt auslesen und Dateiinhalt dann nur einmal als String speichern etc.)?

Vielen Dank!

Hallo!

ich habe folgendes Problem: Ich möchte in meinem Javaprogramm
größere Textdateien (ca. 300, 400 KB, ca. 3000 Zeilen Text)

Bereits bei 4 Dateien braucht das Laden allerdings schon 30
Sekunden.

Dabei erzeugst du 4x3000-mal ein neues String-Objekt. Das ist natürlich „teuer“.

Gibt es da noch was anderes?

StringBuffer bzw. StringBuilder.

Jan

Hallo Jan, vielen Dank.

Das mit dem StringBuffer funktioniert echt super, das Laden dauer jetzt nur noch eine knappe Sekunde ist damit völlig okay. Ich wusste nicht dass es noch was besseres als String gibt.

Ich würde Dir zu StringBuilder raten. StringBuffer ist synchronized und wenn Du nur einen Thread hast, bringen die unsynchronized Methoden des StringBuilders nochmal einen kleinen Vorteil.

kleine erklärung
hallo

strings sind imutable, also unveränderlich. man kann also nicht wie in anderen sprachen zu einem string was dranhängen. man kann lediglich ein neues stringobjekt aus zwei anderen erzeugen.

beispiel:

String s = "a" ;
s = s + "b";

hier erzeugst du insgesammt drei string-objekte: ein objekt mit dem inhalt „a“, eines mit dem inhalt „b“ und eines mit dem inhalt „ab“. in dieser form ist das nicht so tragisch.

String s = "a" ;
for (int i = 0; i 

schaut auf den ersten blick ok aus. ist aber tückisch: die beiden konstanten "a" sind beide das selbe objekt. du erzeugst in der schleife aber 10 neue objekte, nur um einen string mit 11 "a"s zu erhalten. du hast also 11 objekte, von denen 9 eigentlich nur temporär verwendet werden und eigentlich gleich wieder verworfen werden.

objektinstanzierung ist im java das "teuerste" das man machen kann. die vm hat ganz schön viel zu tun, die klassenhierarchien zu prüfen und alles sauber zu instanzieren. dafür muss ja auch speicherplatz freigeschaufelt werden. wird der speicher knapp, muss der garbage collector erst mal den ganzen müll entfernen - was gar nicht so einfach ist, da er ja von allen objekten prüfen muss, ob sie nicht noch irgendwo referenziert werden. kostet alles rechenzeit.

gut - in einer schleife mit nur 10 iterationen braucht man sich um rechenzeit nicht soviel gedanken machen. wäre die obergrenze der iterationen aber durch eine andere variable definiert und es sind durchaus auch tausende iterationen möglich, macht das einen riesen unterschied.

StringBuffer und StringBuilder sind mutable-objekte, können also den inhalt ändern. StringBuffer ist älter und threadsafe, StringBuilder ist relativ neu und nicht threadsafe. ansonsten sind sie identisch. threadsafe bedeutet, dass die zugriffsmethoden auf das objekt synchronized sind - was die geschwindigkeit merklich verlangsamt. wenn du nur innerhalb eines einzelnen threads auf das objekt zugreifst, ist das völlig unnötig. nur bei multithreaded zugriff, der nicht vorher schon explizit synchronisiert wurde, ist die threadsafe-variante sinnvoll. dürfte allerdings nur in weniger als 5 % der fälle sein.

der obige code schaut nun etwa so aus:


    
    StringBuilder s = new StringBuilder("a");
    for (int i = 0; i 
    
    nun hast du nur zwei objekte: die konstante "a" und das StringBuilder-objekt. das instanzieren des StringBuilder-objekts ist zwar etwas langsamer als das instanzieren eines Strings, der unterschied ist aber absolut minimal. auf jeden fall geht das appenden eines strings zu einem StringBuilder weitaus schneller als das erzeugen eines neuen strings. auch hat der garbage collector weitaus weniger zu tun.
    
    es lohnt sich also meist, schon bei recht kleinen string-operationen eine StringBuilder zu verwenden. also, bei operationen wie
    String a = "a" + "b";
    ist ein StringBuilder noch unnötig. sobald du aber sowas in der art hast:
    String a ;
    a += "a";
    ...
    a += "b";
    etc.
    loht sich ein StringBuilder bereits.
    
    lg
    erwin
    
    ps: java-programme haben desshalb den ruf, gähnend langsam zu sein, weil die meisten programmierer von der C-seite kommen, wo es solche probleme in dieser form nicht gibt. die schreiben dann auch meist code, der mit wenigen handgriffen extrem beschleunigt werden kann (z.b. kann das initialisieren eines StringBuilders mit der zu erwartenden maximallänge durchaus im messbaren bereich einen code beschleunigen).