To samozrejme muzete, treba predanim pozadovane velikosti pri konstrukci seznamu (nebo to take delaji metody typu asList() apod). Mel jsem na mysli spis situace, kdy programator nemuze vedet (nebo se mu to nechce slozite zjistovat), kolik dat vlastne dostane a pouzije konstruktor typu new ArrayList().
Bohuzel jste nepochopil podstatu problemu. Mergovat stringy v cyklu neni spatne kvuli realokaci samotne, ale kvuli tomu, ze se musi pokazde vsechna data stale dokola kopirovat.
Rekneme, ze budeme pridavat cisla od 1000 do 9999. Celkovy pocet zkopirovanych znaku pak bude 4x9000x9000/2. To je docela hodne, ze?
StringBuffer/Builder pravuje podobne jako ArrayList. Sice musi taky prealokovat, ale alokuje o blocich vzdy dvojnasobku predchozi delky. Diky tomuto triku se dostava na linearni (amortizovanou) slozitost - 4x9000x2.
Takze odpoved na puvodni otazku je "ano". :-)
Ja jsem odpovidal "pssp" kde jsme se bavili o ArrayListu vs. LinkedListu, toto vlakno prece vubec neni o konkatenaci Stringu ne (tam ke kopirovani samozrejme dochazi, coz je druhy duvod proc jejich konkatenaci ve velkych smyckach nepouzivat)?
Jen pro upresneni - v soucasnosti se pri realokaci nova delka ArrayListu pocita nasledovne:
newCapacity=(oldCapacity*3)/2+1;
U StringBufferu/StringBuilderu je to presne tak jak pisete:
nova kapacita=(stara_kapacita+1)*2
Podle Stephana T. Lavaveje z Microsoftu, který dělá na STL knihovně pro C++ je vhodný násobek pro vector<T> právě 1.5 prý jim to vyšlo nejlépe. http://channel9.msdn.com/Tags/stl
Kdysi jsem někde viděl nějaký benchmark ArrayListu<T>, který se zaměřil na rychlost závislou na počáteční kapacitě. Výsledkem bylo, že je vhodné ArrayList<T> inicializovat "kulatou" hodnotou = mocninou 2. Já často používám 8 nebo 64, samozřejmě jinou hodnotu, pokud zhruba vím, kolik prvků budu potřebovat.
Další volba pro "nafukovací pole" je Vector<T>, od ArrayListu<T> se liší tuším synchronizací a možností zvolit si "koeficient nafukování". Ale nevím to jistě, zájemci ať si přečtou dokumentaci nebo se podívají do implementace. Jo a ohledně rychlosti: čisté pole T[] bude vždy nejrychlejší.
Několikrát jsem omylem při výpisu nebo spojování Stringů napsal toto: System.out.println(str + i + ' ' + str2....); a nestačil jsem se divit kde mám mezeru, dokud jsem si neuvědomil, jak se provede i + ' ' -> int + char = int.
Ok, reagoval jsem na celou diskuzi (vcetne Vasi prvni odpovedi) a tak trochu i na clanek, kde ten duvod, proc je StringBuffer radove rychlejsi, uplne chybi.
Fascinuje me Vas vhled do Javy vcetne prekladu ap., ale trosku mi chybi nadhled. Tady treba zduvodneni, proc je jedna cesta lepsi, jinde je to pochopeni duvodu, proc je Java dosud tak jednoducha a nema moc tech cool scriptovacich vlastnosti (pochopite, kdyz musite navazovat na praci studentu nebo Indu).
Vcera jsem to zapomne zminit, tak to napravim - tyhle clanky jsou velkym prinosem a vzdycky se neco priucim.
Aha, tak to se omlouvam - ja jsem byl z prvniho prispevku teto vetve "naladeny" na druhou kapitolu clanku, kde se prozatim moc o String* nehovorilo, takze v pohode.
S temi novymi vlastnostmi je to, jak pisete, dvousecna zbran, to je pravda - na jednu stranu je mozne v "mocnejsim" jazyku vic prasit (viz napriklad toblibene IOCCC a to je jeste cecko velmi jednoduchy jazyk ;-), na stranu druhou Java kvuli kratsimu "feature listu" ztraci treba oproti C#, takze ho Sun chtel dohnat a predehnat ;-)
Protoze v pripade, ze by Java setrvala na miste, doslo by k jeji cobolizaci (btw dekuji Lukasovi F., ze me na tento vystizny termin upozornil ;-)
Nakonec vime jak Sun dopadl a dusledkem je zpozdeni JDK7 a navic posunuti nekterych novych vlastnosti do JDK8 a vys.